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

来源:互联网 发布:淘宝拍卖的房子利弊 编辑:程序博客网 时间:2024/05/20 15:59

定义:观察者模式就是监听一个对象的变化,当一个对象发生变化时,所有监听其变化的对象都会收到通知,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传递广播

原创粉丝点击