观察者模式在电话中的应用

定义:观察者模式就是监听一个对象的变化,当一个对象发生变化时,所有监听其变化的对象都会收到通知,Android中非常多的东西都是观察者模式的实现。

1.InCallStateListener

incallui,是一个mvp的经典实现,所有的presenter都会监听这个listener

1.1定义

/**
     * Interface implemented by classes that need to know about the InCall State.
     */
    public interface InCallStateListener {
        // TODO: Enhance state to contain the call objects instead of passing CallList
        public void onStateChange(InCallState oldState, InCallState newState, CallList callList);
    }

一个接口,一个回调方法:onStateChange,可以说所有的数据变化都会通过onStateChange通知所有的presenter,之后会更新所有的ui。

1.2流程

以CallButtonPresenter为例,首先是注册:

    @Override
    public void onUiReady(CallButtonUi ui) {
        super.onUiReady(ui);

        mEnhanceEnable = ui.getContext().getResources().getBoolean(
                R.bool.config_enable_enhance_video_call_ui);
        AudioModeProvider.getInstance().addListener(this);

        // register for call state changes last
        final InCallPresenter inCallPresenter = InCallPresenter.getInstance();
        inCallPresenter.addListener(this);
        ...
        // Update the buttons state immediately for the current call
        onStateChange(InCallState.NO_CALLS, inCallPresenter.getInCallState(),
                CallList.getInstance());
    }

    public void addListener(InCallStateListener listener) {
        Preconditions.checkNotNull(listener);
        mListeners.add(listener);
    }

在onUiReady时注册这些listener,onUiReady的回调也可以说是一个观察者模式

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mPresenter.onUiReady(getUi());
    }

在fragment的onActivityCreated时,告知presenter。

    @Override
    public void onCallListChange(CallList callList) {
        if (mInCallActivity != null && mInCallActivity.getCallCardFragment() != null &&
                mInCallActivity.getCallCardFragment().isAnimating()) {
            mAwaitingCallListUpdate = true;
            return;
        }
        if (callList == null) {
            return;
        }

        mAwaitingCallListUpdate = false;

        InCallState newState = getPotentialStateFromCallList(callList);
        InCallState oldState = mInCallState;
        Log.d(this, "onCallListChange oldState= " + oldState + " newState=" + newState);
        newState = startOrFinishUi(newState);
        Log.d(this, "onCallListChange newState changed to " + newState);

        // Set the new state before announcing it to the world
        Log.i(this, "Phone switching state: " + oldState + " -> " + newState);
        mInCallState = newState;

        // notify listeners of new state
        for (InCallStateListener listener : mListeners) {
            Log.d(this, "Notify " + listener + " of state " + mInCallState.toString());
            listener.onStateChange(oldState, mInCallState, callList);
        }

        if (isActivityStarted()) {
            final boolean hasCall = callList.getActiveOrBackgroundCall() != null ||
                    callList.getOutgoingCall() != null;
            mInCallActivity.dismissKeyguard(hasCall);
        }
        if (CallList.getInstance().isDsdaEnabled() && (mInCallActivity != null)) {
            mInCallActivity.updateDsdaTab();
        }
    }

onStateChange的回调时机是onCallListChange,这里又是一个观察者模式,InCallPresenter监听了CallList,onCallListChange的回调时机

    /**
     * Sends a generic notification to all listeners that something has changed.
     * It is up to the listeners to call back to determine what changed.
     */
    private void notifyGenericListeners() {
        for (Listener listener : mListeners) {
            listener.onCallListChange(this);
        }
    }

    /**
     * Called when a single call has changed.
     */
    public void onUpdate(Call call) {
        Trace.beginSection("onUpdate");
        PhoneAccountHandle ph = call.getAccountHandle();
        Log.d(this, "onUpdate - " + call  + " ph:" + ph);
        try {
            if (call.mIsActiveSub && ph != null) {
                int sub = Integer.parseInt(ph.getId());
                Log.d(this, "onUpdate - sub:" + sub + " mSubId:" + mSubId);
                if(sub != mSubId) {
                    setActiveSubId(sub);
                }
            }
        } catch (NumberFormatException e) {
                Log.w(this,"Sub Id is not a number " + e);
        }
        onUpdateCall(call);
        notifyGenericListeners();
        Trace.endSection();
    }
    // onUpdate时notifyGenericListeners

    private void update() {
        Trace.beginSection("Update");
        int oldState = getState();
        // We want to potentially register a video call callback here.
        updateFromTelecomCall(true /* registerCallback */);
        if (oldState != getState() && getState() == Call.State.DISCONNECTED) {
            CallList.getInstance().onDisconnect(this);
        } else {
            CallList.getInstance().onUpdate(this);
        }
        Trace.endSection();
    }
    // 在incallui/Call的update方法调用CallList.getInstance().onUpdate(this);

    private final android.telecom.Call.Callback mTelecomCallCallback =
        new android.telecom.Call.Callback() {
            @Override
            public void onStateChanged(android.telecom.Call call, int newState) {
                Log.d(this, "TelecomCallCallback onStateChanged call=" + call + " newState="
                        + newState);
                update();
            }

            @Override
            public void onParentChanged(android.telecom.Call call,
                    android.telecom.Call newParent) {
                Log.d(this, "TelecomCallCallback onParentChanged call=" + call + " newParent="
                        + newParent);
                update();
            }

            @Override
            public void onChildrenChanged(android.telecom.Call call,
                    List<android.telecom.Call> children) {
                update();
            }

            @Override
            public void onDetailsChanged(android.telecom.Call call,
                    android.telecom.Call.Details details) {
                Log.d(this, "TelecomCallCallback onStateChanged call=" + call + " details="
                        + details);
                update();
            }

            @Override
            public void onCannedTextResponsesLoaded(android.telecom.Call call,
                    List<String> cannedTextResponses) {
                Log.d(this, "TelecomCallCallback onStateChanged call=" + call
                        + " cannedTextResponses=" + cannedTextResponses);
                update();
            }

            @Override
            public void onPostDialWait(android.telecom.Call call,
                    String remainingPostDialSequence) {
                Log.d(this, "TelecomCallCallback onStateChanged call=" + call
                        + " remainingPostDialSequence=" + remainingPostDialSequence);
                update();
            }

            @Override
            public void onVideoCallChanged(android.telecom.Call call,
                    VideoCall videoCall) {
                Log.d(this, "TelecomCallCallback onStateChanged call=" + call + " videoCall="
                        + videoCall);
                update();
            }

            @Override
            public void onCallDestroyed(android.telecom.Call call) {
                Log.d(this, "TelecomCallCallback onStateChanged call=" + call);
                call.unregisterCallback(this);
            }

            @Override
            public void onConferenceableCallsChanged(android.telecom.Call call,
                    List<android.telecom.Call> conferenceableCalls) {
                update();
            }

            @Override
            public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) {
                Log.d(this, "TelecomCallCallback onConnectionEvent call=" + call);
                update();
            }
    };

还是一个观察者模式,incallui/Call监听的是telecom/Call,telecom/Call的变化传递到incallui/Call,incallui/Call的变化传递到CallList的变化,最后导致InCallState的变化。
可以看到整个incallui几乎都是一个观察者模式的实现。

1.3总结

在设计UI的时候观察者模式一定是被优先考虑的,因为Ui就是显示数据的,当数据发生变化时,UI就要实时地发生变换,自然而然就会使用到观察者模式,它的好处就是当数据没有变化时,UI不需要更新,当数据发生变化时,UI又能第一时间收到变化的通知,并更新UI,所以对需要实时更新的UI来讲,观察者模式是一个非常好的模式。

2.广播

Android中广播用的也是非常多,但其实广播其实就是一个观察者模式的实现。通过广播可以突破进程限制,跨进程地通知所有的观察者,所以这个广播是注册在哪里?如果跨进程进行运作。这里简单地看一下广播的注册和接收流程

2.1注册广播

注册广播一般都会食用mContext.registerReceiver(..),最终会调用到ContextImpl的registerReceiverInternal方法

    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context) {
        IIntentReceiver rd = null;//这是一个bindler对象,通过它与AMS交互
        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 {
            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
                    // 这里可以看到调用了ActivityManagerNative的registerReceiver
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

可以看到最终调用了ActivityManagerNative.getDefault().registerReceiver(),所以其实可以猜测广播会注册在AMS中,其中非常重要的一个东西就是IIntentReceiver rd,AMS将通过它来将其他进程发送的广播通知到这个receiver所在的进程,具体在接受广播时在来看ReceiverDispatcher。
AMS中的registerReceiver方法:

    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
        // 省略一些逻辑
        synchronized (this) {
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // Original caller already died
                return null;
            }
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } else if (rl.uid != callingUid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for uid " + callingUid
                        + " was previously registered for uid " + rl.uid);
            } else if (rl.pid != callingPid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for pid " + callingPid
                        + " was previously registered for pid " + rl.pid);
            } else if (rl.userId != userId) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for user " + userId
                        + " was previously registered for user " + rl.userId);
            }
            // 省略sticky的逻辑
        }
    }

可以将这个receiver保存到了mRegisteredReceivers中。这样广播的注册就结束了

2.2发送广播

同样发送广播也会调用到ContextImpl的sendBroadcast方法

    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManagerNative.getDefault().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

又调用到AMS中去broadcastIntent->broadcastIntentLocked->scheduleBroadcastsLocked

    public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

    final class BroadcastHandler extends Handler {
        public BroadcastHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
                case SCHEDULE_TEMP_WHITELIST_MSG: {
                    DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;
                    if (dic != null) {
                        dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),
                                msg.arg2, true, (String)msg.obj);
                    }
                } break;
            }
        }
    }

最后会调用到scheduleRegisteredReceiver

        public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                int resultCode, String dataStr, Bundle extras, boolean ordered,
                boolean sticky, int sendingUser, int processState) throws RemoteException {
            updateProcessState(processState, false);
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }

所以最后还是调用到IIntentReceiver的performReceive方法

        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (intent == null) {
                Log.wtf(TAG, "Null intent received");
            } else {
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                }
            }
            if (intent == null || !mActivityThread.post(args)) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }

z这个args就是一个runable

final class Args extends BroadcastReceiver.PendingResult implements Runnable {
            private Intent mCurIntent;
            private final boolean mOrdered;
            private boolean mDispatched;

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }

            public void run() {
                final BroadcastReceiver receiver = mReceiver;
                final boolean ordered = mOrdered;

                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = mCurIntent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                    Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered
                            + " mOrderedHint=" + ordered);
                }

                final IActivityManager mgr = ActivityManagerNative.getDefault();
                final Intent intent = mCurIntent;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched);
                }

                mCurIntent = null;
                mDispatched = true;
                if (receiver == null || intent == null || mForgotten) {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing null broadcast to " + mReceiver);
                        sendFinished(mgr);
                    }
                    return;
                }

                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
                try {
                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    intent.prepareToEnterProcess();
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);//调用onReceive
                } catch (Exception e) {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing failed broadcast to " + mReceiver);
                        sendFinished(mgr);
                    }
                    if (mInstrumentation == null ||
                            !mInstrumentation.onException(mReceiver, e)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                            "Error receiving broadcast " + intent
                            + " in " + mReceiver, e);
                    }
                }

                if (receiver.getPendingResult() != null) {
                    finish();
                }
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }

可以看到在这里调用了onReceive方法,广播接收完成。中间跳过了非常多的步骤,因为这里的逻辑还是非常的复杂,但是最终原理就是这样,广播注册在AMS中,通过AMS传递广播

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值