On which thread does onReceive() of a BroacastReceiver registered with LocalBroadcastManager run?

后端 未结 2 1691
广开言路
广开言路 2020-12-19 02:38

I register a broadcast receiver in a preference activity and send it a (sync) broadcast from a (Wakeful) IntentService. Apparently onReceive runs on the service\'s thread. I

相关标签:
2条回答
  • 2020-12-19 03:02

    I had been getting the same issue with the sendBroadcastSync(Intent intent) with the LocalBroadcastManager. When I had been trying to update the view from the onReceive(Context context, Intent intent) it threw the below exception:

    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

    Eventually, I came to know that it might not run on the UI thread and hence resorted to using the simple code below:

    public void onReceive(Context context, Intent intent) {
                ....
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        setProgressBar();
                    }
                });
            }
    
    0 讨论(0)
  • 2020-12-19 03:08

    sendBroadcastSync() is indeed run on the thread it is called from (except if there is a race going on). Its implementation should be:

    public void sendBroadcastSync(Intent intent) { // directly calls executePendingBroadcasts
            if (sendBroadcast(intent)) {
                executePendingBroadcasts();
            }
    }
    

    The race part I am not sure about enters via the sendBroadcast() call which returns true if it found any matching receiver (registered with LBM for this intent), after sending a message to a private handler associated with the main loop - abbreviated:

    @Override
    public boolean sendBroadcast(Intent intent) {
        synchronized (mReceivers) {
            final String action = intent.getAction();
            final ArrayList<ReceiverRecord> entries = mActions.get(action);
            if (entries == null) return false; // no receivers for that action
            ArrayList<ReceiverRecord> receivers = new ArrayList<ReceiverRecord>();
            for (ReceiverRecord receiver : entries) {
                if (receiver.broadcasting) continue;
                // match the intent
                int match = receiver.filter.match(action,
                    intent.resolveTypeIfNeeded(mAppContext.getContentResolver()),
                    intent.getScheme(), intent.getData(),
                    intent.getCategories(), "LocalBroadcastManager");
                if (match >= 0) {
                    receivers.add(receiver);
                    receiver.broadcasting = true;
                }
            }
            final int size = receivers.size();
            if (size == 0) return false; // no receivers for this intent
            for (int i = 0; i < size; i++) {
                receivers.get(i).broadcasting = false;
            }
            mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
            if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
                mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
            }
            return true;
        }
    }
    

    where:

        mHandler = new Handler(context.getMainLooper()) {
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_EXEC_PENDING_BROADCASTS:
                        executePendingBroadcasts();
                        break;
                    default:
                        super.handleMessage(msg);
                }
            }
    

    I am not sure if there can be a race between the main thread and the thread sendBroadcastSync() is executing - so the executePendingBroadcasts() will run on the main thread. If not then executePendingBroadcasts() runs on the thread sendBroadcastSync is run and directly calls the onReceive of the receivers

    One of these days I should look into why (in executePendingBroadcasts) synchronized(mReceivers) and not synchronized(mPendingBroadcasts).

    0 讨论(0)
提交回复
热议问题