观察者模式在电话中的应用
来源:互联网 发布:淘宝拍卖的房子利弊 编辑:程序博客网 时间: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传递广播
- 观察者模式在电话中的应用
- 观察者模式在Java编程中的应用
- 观察者模式在项目中的应用
- 观察者模式在安卓中的应用
- 观察者模式在Android中的应用
- 观察者模式在MVP中的应用
- 观察者模式在交易系统中的应用
- 设计模式在游戏中的应用--观察者模式(十)
- 设计模式之观察者模式在Listview中的应用
- 设计模式在游戏开发中的应用之观察者模式
- (转)设计模式之观察者模式在ListView中的应用
- 观察者模式-在wsnos中的应用以及拓展
- Rx框架简介,及在观察者模式中的应用
- 观察者模式(Observer)在Android中的应用:
- spring事件驱动模型--观察者模式在spring中的应用
- JAVA观察者模式在安卓中的应用
- AAAspring事件驱动模型--观察者模式在spring中的应用
- 观察者模式及在Android源码中的应用
- java集合
- 关于我为什么要写博客
- Kth Largest Element in an Array
- 版本更新
- C++
- 观察者模式在电话中的应用
- Mysql数据库操作(六)----单表查询练习
- 交换两个整型变量的值
- 【第二周】项目3-汉诺塔程序
- 在网络中,带宽MB可以写成Mb吗?
- ES6-proxy
- Leetcode 题解系列(一)
- 2017 ACM/ICPC Asia Regional Qingdao Online:1008 Chinese Zodiac
- Linux用PXE自动化安装系统和制作引导盘