微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

android – 在哪一个线程上运行的LocalBroadcastManager注册的BroacastReceiver onReceive()?

我在偏好活动中注册广播接收者,并从(唤醒)IntentService发送(同步)广播.显然onReceive在服务的线程上运行.这是我的错吗?是否记录行为?

偏好活动:

public final class SettingsActivity extends BaseSettings {

    private static CharSequence sMasterKey;
    private CheckBoxPreference mMasterPref;
    // Receiver
    /** If the master preference is changed externally this reacts */
    private broadcastReceiver mExternalChangeReceiver =
        new ExternalChangeReceiver();

    public static void notifyMonitoringStateChange(Context ctx,CharSequence action,boolean isToggling) {
        final LocalbroadcastManager lbm = LocalbroadcastManager
            .getInstance(ctx);
        Intent intent = new Intent(ctx,ExternalChangeReceiver.class);
        intent.setAction(action.toString());
        intent.putExtra(TOGGLING_MONITORING_IN_PROGRESS,isToggling);
        lbm.sendbroadcastSync(intent);
    }

    @Override
    protected void onStart() {
        super.onStart();
        final LocalbroadcastManager lbm = LocalbroadcastManager
            .getInstance(this);
        lbm.registerReceiver(mExternalChangeReceiver,new IntentFilter(
            ac_toggling.toString()));
    }

    @Override
    protected void onStop() {
        // may not be called in Froyo
        final LocalbroadcastManager lbm = LocalbroadcastManager
            .getInstance(this);
        lbm.unregisterReceiver(mExternalChangeReceiver);
        super.onStop();
    }

    private final class ExternalChangeReceiver extends broadcastReceiver {

        ExternalChangeReceiver() {}

        @Override
        @SuppressWarnings("synthetic-access")
        public void onReceive(Context ctx,Intent intent) {
            if (sMasterKey == null || mMasterPref == null) return; // if
            // onPostReceive has not run this will be null
            final String action = intent.getAction();
            if (ac_toggling.equals(action)) {
                final boolean isToggling = intent.getBooleanExtra(
                    TOGGLING_MONITORING_IN_PROGRESS,false);
                Log.w(ExternalChangeReceiver.class.getSimpleName(),"isToggling " + isToggling);
                mMasterPref.setEnabled(!isToggling); // line 168 !!!
                refreshMasterPreference(isToggling);
            }
        }
    }
}

IntentService(LocationMonitor):

SettingsActivity.notifyMonitoringStateChange(this,ac_toggling,true);

异常(E / AndroidRuntime):

FATAL EXCEPTION: IntentService[LocationMonitor]
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4746)
    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:823)
    at android.view.View.requestLayout(View.java:15473)
    at android.view.View.requestLayout(View.java:15473)
    at android.view.View.requestLayout(View.java:15473)
    at android.view.View.requestLayout(View.java:15473)
    at android.view.View.requestLayout(View.java:15473)
    at android.view.View.requestLayout(View.java:15473)
    at android.view.View.requestLayout(View.java:15473)
    at android.view.View.requestLayout(View.java:15473)
    at android.view.View.requestLayout(View.java:15473)
    at android.widget.AbsListView.requestLayout(AbsListView.java:1819)
    at android.widget.AdapterView$AdapterDataSetobserver.onChanged(AdapterView.java:813)
    at android.widget.AbsListView$AdapterDataSetobserver.onChanged(AbsListView.java:5958)
    at android.database.DataSetobservable.notifyChanged(DataSetobservable.java:37)
    at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
    at android.preference.PreferenceGroupAdapter.onPreferenceChange(PreferenceGroupAdapter.java:238)
    at android.preference.Preference.notifyChanged(Preference.java:1099)
    at android.preference.Preference.setEnabled(Preference.java:726)
    at gr.uoa.di.monitoring.android.activities.SettingsActivity$ExternalChangeReceiver.onReceive(SettingsActivity.java:168)
    at android.support.v4.content.LocalbroadcastManager.executePendingbroadcasts(LocalbroadcastManager.java:297)
    at android.support.v4.content.LocalbroadcastManager.sendbroadcastSync(LocalbroadcastManager.java:278)
    at gr.uoa.di.monitoring.android.activities.SettingsActivity.notifyMonitoringStateChange(SettingsActivity.java:54)
    at gr.uoa.di.monitoring.android.services.Monitor.abort(Monitor.java:241)
    at gr.uoa.di.monitoring.android.services.LocationMonitor.doWakefulWork(LocationMonitor.java:103)
    at com.commonsware.cwac.wakeful.WakefulIntentService.onHandleIntent(WakefulIntentService.java:94)
    at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.os.HandlerThread.run(HandlerThread.java:60)

在仿真器API 17上

解决方法

sendbroadcastSync()确实运行在被调用的线程上(除非有比赛进行).其实施 should be
public void sendbroadcastSync(Intent intent) { // directly calls executePendingbroadcasts
        if (sendbroadcast(intent)) {
            executePendingbroadcasts();
        }
}

比赛部分我不确定通过sendbroadcast()调用输入,如果发送消息到与主循环相关联的私有处理程序后发现任何匹配的接收者(用于此意图为LBM注册),则返回true.

@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;
    }
}

哪里:

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);
            }
        }

我不知道主线程和sendbroadcastSync()正在执行的线程之间是否存在竞争 – 所以executePendingbroadcasts()将在主线程上运行.如果不是那么executePendingbroadcasts()运行在线程sendbroadcastSync运行和directly calls接收器的onReceive

其中一个时候,我应该看看为什么(在执行Pendingbroadcasts)同步(mReceivers)而不同步(mPendingbroadcasts).

原文地址:https://www.jb51.cc/android/312531.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐