Search code examples
androiddatabasebroadcastreceiverphotobroadcast

android broadcast receiver doesn`t instantly process broadcast caused a bug after been unregistered


I registered Broadcast receiver when uploading photos via network. Each time uploading a photo successfully, the method broadcasts message to Broadcast Receiver. When Broadcast Receiver receives the message, it will add a cache to local database. I use this logic to ensure no duplicate photos upload.

Until now everything is alright, but when I stop uploading photos (actually photo uploading logic was implemented by Service ), the onDestory() method was invoked and I unregisterd the Broadcast Receiver there and that makes the problem happen.

As we know the broadcast message has some delay time, though one photo was successfully uploaded, did not ensure that Broadcast Receiver instantly add the cache to database on its onReceive() method. If BR did not handle the cache quickly, it may lose the chance to do because when onDestroy() was called, system will unregisterd Broadcast Receiver and the message will be ignored. So there will be one cache missed, and the local database will lack of one cache to ensure no duplicate photos to be uploaded.

code segment one

@Override
public void onCreate() {
    Intent bIntent = new Intent(this, TransferService.class);
    bindService(bIntent, mConnection, Context.BIND_AUTO_CREATE);        
    LocalBroadcastManager.getInstance(this).registerReceiver(transferReceiver,
            new IntentFilter(TransferService.BROADCAST_ACTION));
}


@Override
public void onDestroy() {
    if (mTransferService != null) {
        unbindService(mConnection);
        mTransferService = null;
    }
    LocalBroadcastManager.getInstance(this).unregisterReceiver(transferReceiver);
}

code segment two

private BroadcastReceiver transferReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (mTransferService == null) {
            return;
        }

        String type = intent.getStringExtra("type");
        if (type == null) {
            return;
        }
        if (type.equals(TransferService.BROADCAST_FILE_UPLOAD_SUCCESS)) {
            int taskID = intent.getIntExtra("taskID", 0);
            UploadTaskInfo info = mTransferService.getUploadTaskInfo(taskID);

            if (info != null) {
                cUploadManager.onPhotoUploadSuccess(info.repoName,
                        info.repoID, info.localFilePath
                                .substring(info.localFilePath
                                        .lastIndexOf(DIR)));
            }
        }

    }

};

click here to view the complete source code

So anyone can give some advice to go through this problem, since broadcast receiver caused off by one bug, do I need to change to use handler instead? ? waiting for your advice, and thanks!


Solution

  • It is because the transfer service here is multi-thread, which means once the thread was started by main thread, the main thread lost control of it. So you can not track the uploading status. Even user already turned off the upload service, destroy the BroadcastReceiver, the sub-thread can still exist and continue to upload. Obliviously, to use the BroadcastReceiver to add cache, it will definitely lose one cache.

    The bug above was caused by the BroadcastReceiver can not ensure that it always process the broadcast message (add cache to local db) because it will be destroyed by main thread when sub-thread still exist and continue to send broadcast.

    the solution here is to add cache in sub-thread itself. When finished uploading (upload state is FINISHED) then add a cache inside the sub-thread.