[컴][안드로이드] registerReceiver 관련 참고사항, 소스 코드



registerReceiver 를 여러번 호출하면 어떻게 될까?

같은 receiver 를 가지고 여러번 registerReceiver 를 호출해도 호출은 된다. 그러나 unregister 를 하지않으면 leak 이 된다.

unregisterReceiver 를 하는 방법



해결책으로 아래 2가지를 이야기 한다.
  1. register 할 때 놓을 때 flag 를 하나 둔다.
  2. 여기서 해결책으로 onReceive() 가 호출된 후에 함수내에서 바로 unregisterReceiver 를 호출하도록 구현하는 방법을 이야기 한다.

등록해 놓고, 등록을 해지 못한 상태로 다시 등록을 하게 되는 경우가 있다면 2번째 방법을 고려해 보는 것도 좋은 방법일 듯 싶다. 그런데 onReceive 가 호출되지 않는 경우에 unregister 를 하지 않는다는 문제가 있다.


참고로, 등록되지 않은 receiver 를 unregister 하면 아래와 같은 Exception 이 발생한다.
Caused by: java.lang.IllegalArgumentException: Receiver not registered: com.xxxx.player.Mp3PlayerService$5@40f059a8


flag 사용하는 예제


private void unregisterCallReceiver(){
        if(mIsReceiverRegistered){
            unregisterReceiver(mCallReceiver);
            mIsReceiverRegistered = false;
        }
    }

private void registerCallReceiver(){
    if(!mIsReceiverRegistered){
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.intent.action.PHONE_STATE");
        registerReceiver(mCallReceiver, filter);

        mIsReceiverRegistered = true;
    }
}


registerReceiver source codes

루틴이 startService 를 호출할 때와 같은 routine 이다.

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return registerReceiver(receiver, filter, null, null);
}

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler) {
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext());
}

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
        IntentFilter filter, String broadcastPermission,
        Handler scheduler, Context context) {
    IIntentReceiver rd = null;
    if (receiver != null) {
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = mPackageInfo.getReceiverDispatcher(
                receiver, context, scheduler,
                mMainThread.getInstrumentation(), true);
        } else {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = new LoadedApk.ReceiverDispatcher(
                    receiver, context, scheduler, null, true).getIIntentReceiver();
        }
    }
    try {
        return ActivityManagerNative.getDefault().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName,
                rd, filter, broadcastPermission, userId);
    } catch (RemoteException e) {
        return null;
    }
}

public Intent registerReceiver(IApplicationThread caller, String packageName,
        IIntentReceiver receiver,
        IntentFilter filter, String perm, int userId) throws RemoteException
{
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(packageName);
    data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
    filter.writeToParcel(data, 0);
    data.writeString(perm);
    data.writeInt(userId);
    mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
    reply.readException();
    Intent intent = null;
    int haveIntent = reply.readInt();
    if (haveIntent != 0) {
        intent = Intent.CREATOR.createFromParcel(reply);
    }
    reply.recycle();
    data.recycle();
    return intent;
}



See Also

  1. Broadcast Receiver에 대해서| 안드로이드 기본 강좌, 2011.09.15.







댓글 없음:

댓글 쓰기