activity详解(二 源码篇)
想要剖析一个activity灵魂深处的秘密,必然要从“召唤”它的地方开始,一步一步跟踪到它结束,那么现在让我们在源码内一步一步了解他的整个生命周期吧
一般来说,我们打开一个activity的方式是使用startActivity方法来打开一个Activity类的子类,所以查看第一个方法
/** * Same as {@link #startActivity(Intent, Bundle)} with no options * specified. * 和startActivity(Intent, Bundle)方法相同,只不过没有定义Bundle * * @param intent The intent to start. * * @throws android.content.ActivityNotFoundException * * @see {@link #startActivity(Intent, Bundle)} * @see #startActivityForResult */ @Override public void startActivity(Intent intent) { this.startActivity(intent, null); }
这里我们可以知道,其实在传入一个intent参数之后startActivity方法后,其实它的内部又会调用一个不同参的startActivity的重载方法,那么继续查看这个方法
/** * Launch a new activity. You will not receive any information about when * the activity exits. This implementation overrides the base version, * providing information about * the activity performing the launch. Because of this additional * information, the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag is not * required; if not specified, the new activity will be added to the * task of the caller. * 启动一个新的activity.而在该activity退出时,你将不会收到任何信息. * 它实现并重写了基础版本,提供activity准备启动时的信息, * 因为附加的启动flag没有被强制要求需要填写,如果没有设置的话,新的activity将会被加入到调用的task栈内. * (结合下文可知,启动flag,类似FLAG_ACTIVITY_NEW_TASK的,定义的是activity的启动方式,和activity的四种启动模式有关) * * <p>This method throws {@link android.content.ActivityNotFoundException} * if there was no Activity found to run the given Intent. * * @param intent The intent to start. * @param options Additional options for how the Activity should be started. * See {@link android.content.Context#startActivity(Intent, Bundle) * Context.startActivity(Intent, Bundle)} for more details. * * @throws android.content.ActivityNotFoundException * * @see {@link #startActivity(Intent)} * @see #startActivityForResult */ @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); } }
可以看到因为使用startActivity(intent),我们一般调用的都会是startActivityForResult(intent, -1),那么startActivityForResult方法是什么呢
/** * Same as calling {@link #startActivityForResult(Intent, int, Bundle)} * with no options. * * @param intent The intent to start. * @param requestCode If >= 0, this code will be returned in * onActivityResult() when the activity exits. * requestCode如果大于1,那么在activity结束后,会在onActivityResult()方法中返回这个code值 * (默认传入的是-1,所以不会在activity结束后返回code值) * * @throws android.content.ActivityNotFoundException * * @see #startActivity */ public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) { startActivityForResult(intent, requestCode, null); }
得,又是一个重载方法
/** * Launch an activity for which you would like a result when it finished. * When this activity exits, your * onActivityResult() method will be called with the given requestCode. * Using a negative requestCode is the same as calling * {@link #startActivity} (the activity is not launched as a sub-activity). * 如果你想启动一个结束时带有结果返回值的activity,你需要调用onActivityResult() 方法及传入的requestCode值. * 使用负数作为requestCode的话将会和调用startActivity方法的结果一样(该activity并不会作为子activity启动,我的理解是结束时并不会有返回值) * * <p>Note that this method should only be used with Intent protocols * that are defined to return a result. In other protocols (such as * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may * not get the result when you expect. For example, if the activity you * are launching uses the singleTask launch mode, it will not run in your * task and thus you will immediately receive a cancel result. * * <p>As a special case, if you call startActivityForResult() with a requestCode * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your * activity, then your window will not be displayed until a result is * returned back from the started activity. This is to avoid visible * flickering when redirecting to another activity. * * <p>This method throws {@link android.content.ActivityNotFoundException} * if there was no Activity found to run the given Intent. * * @param intent The intent to start. * @param requestCode If >= 0, this code will be returned in * onActivityResult() when the activity exits. * @param options Additional options for how the Activity should be started. * See {@link android.content.Context#startActivity(Intent, Bundle) * Context.startActivity(Intent, Bundle)} for more details. * * @throws android.content.ActivityNotFoundException * * @see #startActivity */ public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { 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) { // 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. mStartedActivity = true; } cancelInputsAndStartExitTransition(options); // TODO Consider clearing/flushing other event sources and events for child windows. } else { if (options != null) { mParent.startActivityFromChild(this, intent, requestCode, options); } else { // Note we want to go through this method for compatibility with // existing applications that may have overridden it. mParent.startActivityFromChild(this, intent, requestCode); } } }
我觉得要看懂这一段代码,首先我们得知道mParent是个啥,为什么这边要判断是否是null
如果往上翻,我们可以看到mParent是个Activity,并且有两个和他相关的方法
/** Is this activity embedded inside of another activity? */ //这个activity是不是内嵌在其他activity之内的 public final boolean isChild() { return mParent != null; } /** Return the parent activity if this view is an embedded child. */ //如果这个activity是被内嵌的子activity,返回其父activity public final Activity getParent() { return mParent; }
一般而言都不会被内嵌,所以我们看if内的代码即可
//如果父activity为空 if (mParent == null) { //可以看到想要继续分析acticity的启动过程,必须要从Instrumentation.ActivityResult入手了 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()); } //如果requestCode大于等于0,则是需要返回的code的,那么将mStartedActivity if (requestCode >= 0) { // 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. mStartedActivity = true; } //为子窗口考虑清理/刷新其他事件源及事件 cancelInputsAndStartExitTransition(options); // TODO Consider clearing/flushing other event sources and events for child windows.
那么继续追,往Instrumentation类深入,看看execStartActivity方法究竟是啥
/** * Execute a startActivity call made by the application. The default * implementation takes care of updating any active {@link ActivityMonitor} * objects and dispatches this call to the system activity manager; you can * override this to watch for the application to start an activity, and * modify what happens when it does. * 完成应用程序发起的startActivity方法的调用。默认实现负责更新任何活动对象并将此调用分派给系统activity管理器; * 你可以重写它然后观察应用启动activity的过程,然后看看它会发生什么 * * <p>This method returns an {@link ActivityResult} object, which you can * use when intercepting application calls to avoid performing the start * activity action but still return the result the application is * expecting. To do this, override this method to catch the call to start * activity so that it returns a new ActivityResult containing the results * you would like the application to see, and don't call up to the super * class. Note that an application is only expecting a result if * <var>requestCode</var> is >= 0. * * <p>This method throws {@link android.content.ActivityNotFoundException} * if there was no Activity found to run the given Intent. * * @param who The Context from which the activity is being started. * who 正在开启activity的activity的上下文对象context * @param contextThread The main thread of the Context from which the activity * is being started. * contextThread 正在开启activity的activity的上下文对象context的主线程 * @param token Internal token identifying to the system who is starting * the activity; may be null. * token 正在启动activity的系统的内部令牌标示;可能是null * @param target Which activity is performing the start (and thus receiving * any result); may be null if this call is not being made * from an activity. * target 哪个activity正在被执行启动(并且会接收任何结果);如果调用不是从另外一个activity发起的,它可能会是null * @param intent The actual Intent to start. * intent 开始的实际意图(其实没啥翻译的,intent就是intent,意图) * @param requestCode Identifier for this request's result; less than zero * if the caller is not expecting a result. * requestCode 为了请求的结果而定义;如果不期待结果,则该值定义小于零即可 * @param options Addition options. * options 添加的操作 * * @return To force the return of a particular result, return an * ActivityResult object containing the desired data; otherwise * return null. The default implementation always returns null. * 强制返回一个特殊的结果,返回一个包含所需数据的ActivityResult对象;否则返回null。默认实现总是返回null。 * * @throws android.content.ActivityNotFoundException * * @see Activity#startActivity(Intent) * @see Activity#startActivityForResult(Intent, int) * @see Activity#startActivityFromChild * * {@hide} */ public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { //正在开启activity的activity的上下文对象context的主线程 IApplicationThread whoThread = (IApplicationThread) contextThread; //定义一个referrer(引荐?),其值为target是否为空,不为空则是target.onProvideReferrer(),为空则也为空 Uri referrer = target != null ? target.onProvideReferrer() : null; //如果referrer不为空,将其放入intent if (referrer != null) { intent.putExtra(Intent.EXTRA_REFERRER, referrer); } //如果mActivityMonitors(activity监控器)不为空 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()) { //如果requestCode大于等于0,ActivityMonitor则会调用am.getResult()方法 //猜测返回结果即是用ActivityMonitor监控activity状态,然后获取结果,然后返回给父activity return requestCode >= 0 ? am.getResult() : null; } break; } } } } try { //处理extra流 intent.migrateExtraStreamToClipData(); //做好intent的准备以离开程序进程 intent.prepareToLeaveProcess(who); int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); //检查返回的result的code是哪种情况,以判断activity是否被成功开启 checkStartActivityResult(result, intent); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } return null; }
可以看到该try代码块中的ActivityManagerNative.getDefault().startActivity()方法才是开启activity的核心代码,继续深入观察它在干什么
来到ActivityManagerNative类
可以看到ActivityManagerNative.getDefault().startActivity()中的getDefault()是一个get方法,返回activity管理器(继续跟下去的话会发现getDefault()方法其实只是为了找到唯一的那个实例对象)
/** * Retrieve the system's default/global activity manager. */ static public IActivityManager getDefault() { return gDefault.get(); }
重点其实在startActivity()方法中,startActivity()方法其实是ActivityManagerNative类中内嵌类ActivityManagerProxy的一个公有方法
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是一种存放读取数据的容器,目测应该可以理解为一个封装好的数据类,它是轻量且高效的对象序列化和反序列化机制 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); } //只研究activity的启动的话,不用太在意上面的代码,粗略一看,知道是往Parcel里面写数据即可 //附带START_ACTIVITY_TRANSACTION的code及上面填好的data数据,执行transact()方法 mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0); reply.readException(); int result = reply.readInt(); reply.recycle(); data.recycle(); return result; }
于是往transact()方法继续追,会发现transact()方法是ActivityManagerNative父类Binder的方法
/** * Default implementation rewinds the parcels and calls onTransact. On * the remote side, transact calls into the binder to do the IPC. * 默认实现会发回封装好的data数据(Parcel类)并且调用onTransact()方法。 * 在远程方面,在Binder中处理调用已完成进程间通信(IPC) */ public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } //这里调用了onTransact()方法,并且将之前传入的code和data又发送出去 boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; }
那么onTransact()方法又在哪呢,Binder内有,但是其实具体的实现被其子类ActivityManagerNative重写了
于是又回到ActivityManagerNative类,由于该方法过长,我们只看其中的一部分,之前传入了一个code,即START_ACTIVITY_TRANSACTION,在ActivityManagerNative类中的onTransact()方法中有一个switch用于执行具体code的具体方法,所以我们研究START_ACTIVITY_TRANSACTION的这一段即可
@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; }
}
return super.onTransact(code, data, reply, flags);
}