Android startActivity原始碼分析
靜下心來打算看看android原始碼,就從startActivity這個最常見的函式開始一步步分析下去。
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
首先看到startActivity 呼叫一個過載的方法,第二個Bundle 傳null;
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
可以看到Bundle options 這個入參為null 會走到 startActivityForResult(intent, -1);
我們繼續看
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
如上面那註釋說的一樣,只是通過這個呼叫來相容。這裡我們可以看出歸根結底都是呼叫startActivityForResult。
接下來看看startActivityForResult方法,考慮到篇幅,註釋已經去掉了。。
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);
}
}
}
看到第一行if(mParent == null)這個mParent是什麼鬼。定位一下!!!
/*package*/ ActivityInfo mActivityInfo;
/*package*/ ActivityThread mMainThread;
Activity mParent;
boolean mCalled;
/*package*/ boolean mResumed;
/*package*/ boolean mStopped;
在成員變數裡看到了它,大家都知道ActivityGroup這玩意,所以看這個activity之間也有了父子關係。我們今天先看一般情況走進if(mParent == null)。又看到一個么蛾子
transferSpringboardActivityOptions(options); 字面翻譯 傳送跳板活動選項。。。來挖掘下它的作用
private Bundle transferSpringboardActivityOptions(Bundle options) {
if (options == null && (mWindow != null && !mWindow.isActive())) {
final ActivityOptions activityOptions = getActivityOptions();
if (activityOptions != null &&
activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
return activityOptions.toBundle();
}
}
return options;
}
當options為空,窗體不為空,且不在活動中。。。看到一個東西ActivityOptions ,百度一下原來是轉場動畫。
有興趣可以看下Android 使用ActivityOptions實現Activity轉場動畫
花裡胡哨的我們先不深究,回到主邏輯上下面一大段
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
新朋友 Instrumentation 英文解釋 n. 使用儀器,裝設儀器; 樂器法; 樂曲研究; 手段;
在繼續深入探索之前,我們先把其他邊邊角角的內容稍微解釋下
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
private void cancelInputsAndStartExitTransition(Bundle options) {
final View decor = mWindow != null ? mWindow.peekDecorView() : null;
if (decor != null) {
decor.cancelPendingInputEvents();
}
if (options != null && !isTopOfTask()) {
mActivityTransitionState.startExitOutTransition(this, options);
}
}
除了後面的動畫取消輸入事件,對之前ar!=null 之後sendActivityResult 有段註釋可以看看
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
大概就是呼叫start是為了圖個結果。。。
用android studio 看原始碼會發現看到mInstrumentation.execStartActivity 冒紅,點不進去。
這是谷歌不讓你看, 需要藉助外力 Android Studio 檢視Android內部隱藏原始碼
繼續
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else 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 = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
這個方法有7個入參,真的挺多的。
who:this
target: this
兩個IBinder
token: 標示自己
contextThread: 看到下一行強轉成IApplicationThread 多麼熟悉,你看它原始碼就知道了binder通訊。跟你自己寫aidl ,系統幫你生成的一樣,跨程序通訊,又類似於遠端方法呼叫,IApplicationThread是一個介面
public interface IApplicationThread extends IInterface {
void schedulePauseActivity(IBinder var1, boolean var2, boolean var3, int var4, boolean var5) throws RemoteException;
void scheduleStopActivity(IBinder var1, boolean var2, int var3) throws RemoteException;
void scheduleWindowVisibility(IBinder var1, boolean var2) throws RemoteException;
void scheduleResumeActivity(IBinder var1, int var2, boolean var3, Bundle var4) throws RemoteException;
void scheduleSendResult(IBinder var1, List<ResultInfo> var2) throws RemoteException;
void scheduleLaunchActivity(Intent var1, IBinder var2, int var3, ActivityInfo var4, Configuration var5, Configuration var6, CompatibilityInfo var7, String var8, IVoiceInteractor var9, int var10, Bundle var11, PersistableBundle var12, List<ResultInfo> var13, List<ReferrerIntent> var14, boolean var15, boolean var16, ProfilerInfo var17) throws RemoteException;
void scheduleNewIntent(List<ReferrerIntent> var1, IBinder var2, boolean var3) throws RemoteException;
void scheduleDestroyActivity(IBinder var1, boolean var2, int var3) throws RemoteException;
void scheduleReceiver(Intent var1, ActivityInfo var2, CompatibilityInfo var3, int var4, String var5, Bundle var6, boolean var7, int var8, int var9) throws RemoteException;
void scheduleCreateService(IBinder var1, ServiceInfo var2, CompatibilityInfo var3, int var4) throws RemoteException;
void scheduleStopService(IBinder var1) throws RemoteException;
void bindApplication(String var1, ApplicationInfo var2, List<ProviderInfo> var3, ComponentName var4, ProfilerInfo var5, Bundle var6, IInstrumentationWatcher var7, IUiAutomationConnection var8, int var9, boolean var10, boolean var11, boolean var12, boolean var13, Configuration var14, CompatibilityInfo var15, Map var16, Bundle var17, String var18) throws RemoteException;
void scheduleExit() throws RemoteException;
void scheduleConfigurationChanged(Configuration var1) throws RemoteException;
void scheduleServiceArgs(IBinder var1, ParceledListSlice var2) throws RemoteException;
void updateTimeZone() throws RemoteException;
void processInBackground() throws RemoteException;
void scheduleBindService(IBinder var1, Intent var2, boolean var3, int var4) throws RemoteException;
void scheduleUnbindService(IBinder var1, Intent var2) throws RemoteException;
void dumpService(ParcelFileDescriptor var1, IBinder var2, String[] var3) throws RemoteException;
void scheduleRegisteredReceiver(IIntentReceiver var1, Intent var2, int var3, String var4, Bundle var5, boolean var6, boolean var7, int var8, int var9) throws RemoteException;
void scheduleLowMemory() throws RemoteException;
void scheduleActivityConfigurationChanged(IBinder var1, Configuration var2) throws RemoteException;
去掉方法的字首名schedule,大家是不是都有似曾相識的感覺。
public abstract static class Stub extends Binder implements IApplicationThread {
private static final String DESCRIPTOR = "android.app.IApplicationThread";
static final int TRANSACTION_schedulePauseActivity = 1;
static final int TRANSACTION_scheduleStopActivity = 2;
static final int TRANSACTION_scheduleWindowVisibility = 3;
static final int TRANSACTION_scheduleResumeActivity = 4;
static final int TRANSACTION_scheduleSendResult = 5;
static final int TRANSACTION_scheduleLaunchActivity = 6;
static final int TRANSACTION_scheduleNewIntent = 7;
static final int TRANSACTION_scheduleDestroyActivity = 8;
......
public Stub() {
this.attachInterface(this, "android.app.IApplicationThread");
}
public static IApplicationThread asInterface(IBinder obj) {
if (obj == null) {
return null;
} else {
IInterface iin = obj.queryLocalInterface("android.app.IApplicationThread");
return (IApplicationThread)(iin != null && iin instanceof IApplicationThread ? (IApplicationThread)iin : new IApplicationThread.Stub.Proxy(obj));
}
}
public IBinder asBinder() {
return this;
}
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
...
多麼的熟悉啊,好啦,就不扯它 了。
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
target.onProvideReferrer方法沒覆寫,是個null.
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else 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 = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
第一行 粗略的判斷是給一些action 加許可權,我們不管。
第二行我們不打算去其他程序不考慮。
重頭戲來了ActivityManager.getService().startActivity 。。。AM出現,
/**
* @hide
*/
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
懶載入的單例模式+範型,單例複習下,很多種,double check, 列