Android中bindService是一個異步的過程,什麼意思呢?使用bindService無非是想得到一個Binder服務的Proxy,但這個代理獲取到的時機並不是由bindService發起端控制,而是由Service端來控制,也就是說bindService以後,APP端並不會馬上得到Proxy,而是要等待Service通知APP端,具體流程可簡化以下:java
經過代碼來看更直接面試
void test(){ bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder); Log.v(TAG, "onServiceConnected..." ); } @Override public void onServiceDisconnected(ComponentName componentName) { } }, Context.BIND_AUTO_CREATE); Log.v(TAG, "end..." ); }
</>架構
bindService的過程當中,上面代碼的Log應該是怎麼樣的呢?若是bindService是一個同步過程,那麼Log應該以下:app
TAG onServiceConnected ... TAG end ...
可是因爲是個異步過程,真實的Log以下異步
TAG end ... TAG onServiceConnected ...
也就是說bindService不會阻塞等待APP端獲取Proxy,而是直接返回,這些均可以從源碼得到支持,略過,直接去ActivityManagerNative去看ide
public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); data.writeStrongBinder(token); service.writeToParcel(data, 0); data.writeString(resolvedType); data.writeStrongBinder(connection.asBinder()); data.writeInt(flags); data.writeInt(userId); mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); data.recycle(); reply.recycle(); return res; }
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0)確實會讓APP端調用線程阻塞,等待AMS執行BIND_SERVICE_TRANSACTION請求,不過AMS在執行這個請求的時候並不是是喚醒Service才返回,它返回的時機更早,接着看ActivityManagerService,函數
public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { ... synchronized(this) { return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, userId); } }
ActivityManagerService直接調用ActiveServices的函數bindServiceLocked,請求綁定Service,到這裏APP端線程依舊阻塞,等待AMS端返回,假定Service所處的進程已經啓動可是Service沒有啓動,這時ActiveServices會進一步調用bindServiceLocked->realStartServiceLocked來啓動Service,有趣的就在這裏:學習
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app) throws RemoteException { ... app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo)); ... requestServiceBindingsLocked(r);
app.thread.scheduleCreateService也是一個Binder通訊過程,他實際上是AMS異步請求ActivityThread中的ApplicationThread服務,系統服務請求客戶端的本地服務通常都是異步的:this
// 插入消息,等待主線程執行 public final void scheduleCreateService(IBinder token, ServiceInfo info, CompatibilityInfo compatInfo) { CreateServiceData s = new CreateServiceData(); s.token = token; s.info = info; s.compatInfo = compatInfo; queueOrSendMessage(H.CREATE_SERVICE, s); }
不過,這個請求直接向Service端的ActivityThread線程中直接插入一個消息就返回了,而並未等到該請求執行,由於AMS使用的很是頻繁,不可能老等待客戶端完成一些任務,因此AMS端向客戶端發送完命令就直接返回,這個時候其實Service尚未被建立,也就是這個請求只是完成了一半,onServiceConnected也並不會執行,onServiceConnected何時執行呢?app.thread.scheduleCreateService向APP端插入第一條消息,是用來建立Service的, requestServiceBindingsLocked其實就是第二條消息,用來處理綁定的spa
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean rebind) { ... r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
第二條消息是處理一些綁定需求,Android的Hanlder消息處理機制保證了第二條消息必定是在第一條消息以後執行,
public final void scheduleBindService(IBinder token, Intent intent, boolean rebind) { BindServiceData s = new BindServiceData(); s.token = token; s.intent = intent; s.rebind = rebind; queueOrSendMessage(H.BIND_SERVICE, s); }
以上兩條消息插入後,AMS端被喚醒,進而從新喚醒以前阻塞的bindService端,而這個時候,Service並不必定被建立,因此說這是個未知的異步過程,Service端處理第一條消息的時會建立Service,
private void handleCreateService(CreateServiceData data) { ... LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance(); ...
執行第二條消息的時候, 會向AMS請求publishService,其實就是告訴AMS,服務啓動完畢,能夠向以前請求APP端派發代理了。
private void handleBindService(BindServiceData data) { Service s = mServices.get(data.token); if (s != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); try { if (!data.rebind) { IBinder binder = s.onBind(data.intent); ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder); ...
AMS端收到publishService消息以後,纔會向APP端發送通知,進而經過Binder回調APP端onServiceConnected函數,同時傳遞Proxy Binder服務代理
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) { ... try { c.conn.connected(r.name, service); } catch (Exception e) {}
到這裏,onServiceConnected纔會被回調,不過,至於Service端那兩條消息何時執行,誰也不能保證,也許由於特殊緣由,那兩條消息永遠不被執行,那onServiceConnected也就不會被回調,可是這不會影響AMS與APP端處理其餘問題,由於這些消息是否被執行已經不能阻塞他們兩個了,簡單流程以下:
bindService的異步流程
最後,其實startService也是異步。
感謝你們能耐着性子,看完我囉哩囉嗦的文章。
願與各位堅守在Android開發崗位的同胞們互相交流學習,共同進步!
在這裏我也分享一份本身收錄整理的Android學習PDF+架構視頻+面試文檔+源碼筆記,還有高級架構技術進階腦圖、Android開發面試專題資料,高級進階架構資料幫助你們學習提高進階,也節省你們在網上搜索資料的時間來學習,也能夠分享給身邊好友一塊兒學習
若是你有須要的話,能夠點贊,關注我