探索startActivity流程及在Activity间是如何传递Intent的
生活随笔
收集整理的這篇文章主要介紹了
探索startActivity流程及在Activity间是如何传递Intent的
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在activity中intent到底是怎么傳遞的,而且還可以跨進程甚至跨app來傳遞,下面我們從源碼層面探索一下
從startActivity開始,源碼如下:
@Override
public void startActivity(Intent intent) {this.startActivity(intent, null);
}@Override
public void startActivity(Intent intent, @Nullable Bundle options) {if (options != null) {startActivityForResult(intent, -1, options);} else {startActivityForResult(intent, -1);}
}
調用到了startActivityForResult函數,源碼如下:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {startActivityForResult(intent, requestCode, null);
}public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {if (mParent == null) {options = transferSpringboardActivityOptions(options);Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);if (ar != null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());}if (requestCode >= 0) {mStartedActivity = true;}cancelInputsAndStartExitTransition(options);} else {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {mParent.startActivityFromChild(this, intent, requestCode);}}
}
可以看到如果有parent,那么調用parent的startActivityFromChild,沒有直接進行處理。可以想象parent的startActivityFromChild應該是同樣的邏輯,有興趣的可以去看看源碼。
當沒parent時則使用mInstrumentation的execStartActivity函數來處理,mInstrumentation是一個Instrumentation對象,它的execStartActivity源碼如下:
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, String target,Intent intent, int requestCode, Bundle options) {IApplicationThread whoThread = (IApplicationThread) contextThread;if (mActivityMonitors != null) {synchronized (mSync) {final int N = mActivityMonitors.size();for (int i=0; i<N; i++) {final ActivityMonitor am = mActivityMonitors.get(i);if (am.match(who, null, intent)) {am.mHits++;if (am.isBlocking()) {return requestCode >= 0 ? am.getResult() : null;}break;}}}}try {intent.migrateExtraStreamToClipData();intent.prepareToLeaveProcess(who);int result = ActivityManagerNative.getDefault().startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target, requestCode, 0, null, options);checkStartActivityResult(result, intent);} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);}return null;
}
在最后幾句代碼可以看到調用了ActivityManagerNative.getDefault().startActivity,ActivityManagerNative.getDefault()會得到的一個ActivityManagerProxy對象(IActivityManager接口),這個類在ActivityManagerNative中,它的startActivity函數源碼如下:
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);data.writeString(callingPackage);intent.writeToParcel(data, 0);data.writeString(resolvedType);data.writeStrongBinder(resultTo);data.writeString(resultWho);data.writeInt(requestCode);data.writeInt(startFlags);if (profilerInfo != null) {data.writeInt(1);profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);} else {data.writeInt(0);}if (options != null) {data.writeInt(1);options.writeToParcel(data, 0);} else {data.writeInt(0);}mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);reply.readException();int result = reply.readInt();reply.recycle();data.recycle();return result;
}
在這個函數中將一系列信息包裝到Parcel中(包括intent),然后調用了mRemote.transact函數。同時,注意這里transact的第一個參數傳的是START_ACTIVITY_TRANSACTION,這是一個code,在下面會用到。
這樣我們就碰觸到了IBinder機制,IBinder很多文章都分析過,這里根據我的理解大概簡單講一下。 IBinder機制主要實現在底層(c++),通過它來實現進程間的通信. 簡單來說是一端作為service,另一端作為client(實際上都是service,只不過在不同的情況下角色不同,都可以轉換) (1)消息發出方,即客戶端的service通過BpBinder(在這個流程中就是代碼中的mRemote)打開/dev/binder設備(linux的一塊內核空間,實際上就是共享內存),并將信息寫入(即IBinder的transact函數)。 (2)消息接收方,即服務端的service會開啟循環線程(其實從注冊后就開始了),通過BBinder(在這個流程中是一個ActivityManagerNative對象,下面會講到)不停的從/dev/binder設備中讀取信息,然后根據信息做相應的處理(IBinder的onTransact函數) (3)這時當原客戶端從/dev/binder設備得到對方已收到的信息后,角色轉換為服務端,等待回復即replay(同樣循環線程)。 (4)當原服務端處理后需要回復時,角色轉為客戶端,發送回復。 這樣就實現了跨進程的通信。 因為是通過binder,所以我們的消息如intent之類都要包裝成binder支持的Parcel,這也是intent只能傳遞可系列化對象的原因。同時因為這塊共享內存大小的限制,也就導致了intent傳遞數據的大小限制(關于Parcel和大小限制請閱讀:Android中Intent/Bundle的通信原理及大小限制一文)。 同樣因為binder機制,我們不僅可以啟動本app中的activity(自己同時是客戶端和服務端),也可以啟動其他app中公開的acitivity。
ActivityManagerNative類實際上繼承了Binder(IBinder接口),也就是上面提到的BBinder的角色。當接收并解析binder消息后會調用它的onTransact來進行處理,在ActivityManagerNative中onTransact非常龐大,根據code做不同的處理,我們只需要關注START_ACTIVITY_TRANSACTION這個code即可。 @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags)throws RemoteException {switch (code) {case START_ACTIVITY_TRANSACTION:{data.enforceInterface(IActivityManager.descriptor);IBinder b = data.readStrongBinder();IApplicationThread app = ApplicationThreadNative.asInterface(b);String callingPackage = data.readString();Intent intent = Intent.CREATOR.createFromParcel(data);String resolvedType = data.readString();IBinder resultTo = data.readStrongBinder();String resultWho = data.readString();int requestCode = data.readInt();int startFlags = data.readInt();ProfilerInfo profilerInfo = data.readInt() != 0? ProfilerInfo.CREATOR.createFromParcel(data) : null;Bundle options = data.readInt() != 0? Bundle.CREATOR.createFromParcel(data) : null;int result = startActivity(app, callingPackage, intent, resolvedType,resultTo, resultWho, requestCode, startFlags, profilerInfo, options);reply.writeNoException();reply.writeInt(result);return true;}... } 拿到Parcel類型的數據,然后反系列化解析成Intent等,最后調用startActivity,但是在ActivityManagerNative并沒有找到這個函數,那是因為ActivityManagerNative是一個抽象類,真正的實現是在它的子類ActivityManagerService中,然后通過ApplicationTreadProxy等類啟動activity。這部分不是我們本文的重點,而且比較復雜,就不詳細說了。借用網上一張時序圖來展示一下這個流程。
這樣我們就碰觸到了IBinder機制,IBinder很多文章都分析過,這里根據我的理解大概簡單講一下。 IBinder機制主要實現在底層(c++),通過它來實現進程間的通信. 簡單來說是一端作為service,另一端作為client(實際上都是service,只不過在不同的情況下角色不同,都可以轉換) (1)消息發出方,即客戶端的service通過BpBinder(在這個流程中就是代碼中的mRemote)打開/dev/binder設備(linux的一塊內核空間,實際上就是共享內存),并將信息寫入(即IBinder的transact函數)。 (2)消息接收方,即服務端的service會開啟循環線程(其實從注冊后就開始了),通過BBinder(在這個流程中是一個ActivityManagerNative對象,下面會講到)不停的從/dev/binder設備中讀取信息,然后根據信息做相應的處理(IBinder的onTransact函數) (3)這時當原客戶端從/dev/binder設備得到對方已收到的信息后,角色轉換為服務端,等待回復即replay(同樣循環線程)。 (4)當原服務端處理后需要回復時,角色轉為客戶端,發送回復。 這樣就實現了跨進程的通信。 因為是通過binder,所以我們的消息如intent之類都要包裝成binder支持的Parcel,這也是intent只能傳遞可系列化對象的原因。同時因為這塊共享內存大小的限制,也就導致了intent傳遞數據的大小限制(關于Parcel和大小限制請閱讀:Android中Intent/Bundle的通信原理及大小限制一文)。 同樣因為binder機制,我們不僅可以啟動本app中的activity(自己同時是客戶端和服務端),也可以啟動其他app中公開的acitivity。
ActivityManagerNative類實際上繼承了Binder(IBinder接口),也就是上面提到的BBinder的角色。當接收并解析binder消息后會調用它的onTransact來進行處理,在ActivityManagerNative中onTransact非常龐大,根據code做不同的處理,我們只需要關注START_ACTIVITY_TRANSACTION這個code即可。 @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags)throws RemoteException {switch (code) {case START_ACTIVITY_TRANSACTION:{data.enforceInterface(IActivityManager.descriptor);IBinder b = data.readStrongBinder();IApplicationThread app = ApplicationThreadNative.asInterface(b);String callingPackage = data.readString();Intent intent = Intent.CREATOR.createFromParcel(data);String resolvedType = data.readString();IBinder resultTo = data.readStrongBinder();String resultWho = data.readString();int requestCode = data.readInt();int startFlags = data.readInt();ProfilerInfo profilerInfo = data.readInt() != 0? ProfilerInfo.CREATOR.createFromParcel(data) : null;Bundle options = data.readInt() != 0? Bundle.CREATOR.createFromParcel(data) : null;int result = startActivity(app, callingPackage, intent, resolvedType,resultTo, resultWho, requestCode, startFlags, profilerInfo, options);reply.writeNoException();reply.writeInt(result);return true;}... } 拿到Parcel類型的數據,然后反系列化解析成Intent等,最后調用startActivity,但是在ActivityManagerNative并沒有找到這個函數,那是因為ActivityManagerNative是一個抽象類,真正的實現是在它的子類ActivityManagerService中,然后通過ApplicationTreadProxy等類啟動activity。這部分不是我們本文的重點,而且比較復雜,就不詳細說了。借用網上一張時序圖來展示一下這個流程。
?
總結
以上是生活随笔為你收集整理的探索startActivity流程及在Activity间是如何传递Intent的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一步一步自定义spinner
- 下一篇: Bundle/Intent传递序列化参数