|
| 1 | +Activity启动过程 |
| 2 | +=== |
| 3 | + |
| 4 | +前两天面试了天猫的开发,被问到了`Activity`启动过程,不懂啊.... |
| 5 | +今天就来分析一下,我们开启`Activity`主要有两种方式: |
| 6 | + |
| 7 | +- 通过桌面图标启动,桌面就是`Launcher`其实他也是一个应用程序,他也是继承`Activity`。 |
| 8 | +- 在程序内部调用`startActivity()`开启。 |
| 9 | + |
| 10 | +而`Launcher`点击图标其实也是调用了`Activity`的`startActivity()`方法,所以我们就从`startActivity()`方法入手了。 |
| 11 | +首先看一下`Activity`类中的`startActivity()`方法: |
| 12 | +```java |
| 13 | +@Override |
| 14 | +public void startActivity(Intent intent) { |
| 15 | + this.startActivity(intent, null); |
| 16 | +} |
| 17 | +``` |
| 18 | +继续看`startActivity(intent, null)`: |
| 19 | +```java |
| 20 | +/** |
| 21 | + * Launch a new activity. You will not receive any information about when |
| 22 | + * the activity exits. This implementation overrides the base version, |
| 23 | + * providing information about |
| 24 | + * the activity performing the launch. Because of this additional |
| 25 | + * information, the {@link Intent#FLAG_ACTIVITY_NEW_TASK} launch flag is not |
| 26 | + * required; if not specified, the new activity will be added to the |
| 27 | + * task of the caller. |
| 28 | + * |
| 29 | + * <p>This method throws {@link android.content.ActivityNotFoundException} |
| 30 | + * if there was no Activity found to run the given Intent. |
| 31 | + * |
| 32 | + * @param intent The intent to start. |
| 33 | + * @param options Additional options for how the Activity should be started. |
| 34 | + * See {@link android.content.Context#startActivity(Intent, Bundle) |
| 35 | + * Context.startActivity(Intent, Bundle)} for more details. |
| 36 | + * |
| 37 | + * @throws android.content.ActivityNotFoundException |
| 38 | + * |
| 39 | + * @see {@link #startActivity(Intent)} |
| 40 | + * @see #startActivityForResult |
| 41 | + */ |
| 42 | +@Override |
| 43 | +public void startActivity(Intent intent, @Nullable Bundle options) { |
| 44 | + if (options != null) { |
| 45 | + startActivityForResult(intent, -1, options); |
| 46 | + } else { |
| 47 | + // Note we want to go through this call for compatibility with |
| 48 | + // applications that may have overridden the method. |
| 49 | + startActivityForResult(intent, -1); |
| 50 | + } |
| 51 | +} |
| 52 | +``` |
| 53 | +接下来会调用`startActivityForResult()`方法(注释也很重要啊,里面也说明了singleTask启动模式时该方法不会走到回调中): |
| 54 | +```java |
| 55 | +/** |
| 56 | + * Launch an activity for which you would like a result when it finished. |
| 57 | + * When this activity exits, your |
| 58 | + * onActivityResult() method will be called with the given requestCode. |
| 59 | + * Using a negative requestCode is the same as calling |
| 60 | + * {@link #startActivity} (the activity is not launched as a sub-activity). |
| 61 | + * |
| 62 | + * <p>Note that this method should only be used with Intent protocols |
| 63 | + * that are defined to return a result. In other protocols (such as |
| 64 | + * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may |
| 65 | + * not get the result when you expect. For example, if the activity you |
| 66 | + * are launching uses the singleTask launch mode, it will not run in your |
| 67 | + * task and thus you will immediately receive a cancel result. |
| 68 | + * |
| 69 | + * <p>As a special case, if you call startActivityForResult() with a requestCode |
| 70 | + * >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your |
| 71 | + * activity, then your window will not be displayed until a result is |
| 72 | + * returned back from the started activity. This is to avoid visible |
| 73 | + * flickering when redirecting to another activity. |
| 74 | + * |
| 75 | + * <p>This method throws {@link android.content.ActivityNotFoundException} |
| 76 | + * if there was no Activity found to run the given Intent. |
| 77 | + * |
| 78 | + * @param intent The intent to start. |
| 79 | + * @param requestCode If >= 0, this code will be returned in |
| 80 | + * onActivityResult() when the activity exits. |
| 81 | + * @param options Additional options for how the Activity should be started. |
| 82 | + * See {@link android.content.Context#startActivity(Intent, Bundle) |
| 83 | + * Context.startActivity(Intent, Bundle)} for more details. |
| 84 | + * |
| 85 | + * @throws android.content.ActivityNotFoundException |
| 86 | + * |
| 87 | + * @see #startActivity |
| 88 | + */ |
| 89 | +public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { |
| 90 | + // mParent也是Activity类,通过名字就能看明白了。 |
| 91 | + if (mParent == null) { |
| 92 | + // 开始了啊 |
| 93 | + Instrumentation.ActivityResult ar = |
| 94 | + mInstrumentation.execStartActivity( |
| 95 | + this, mMainThread.getApplicationThread(), mToken, this, |
| 96 | + intent, requestCode, options); |
| 97 | + if (ar != null) { |
| 98 | + mMainThread.sendActivityResult( |
| 99 | + mToken, mEmbeddedID, requestCode, ar.getResultCode(), |
| 100 | + ar.getResultData()); |
| 101 | + } |
| 102 | + if (requestCode >= 0) { |
| 103 | + // If this start is requesting a result, we can avoid making |
| 104 | + // the activity visible until the result is received. Setting |
| 105 | + // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the |
| 106 | + // activity hidden during this time, to avoid flickering. |
| 107 | + // This can only be done when a result is requested because |
| 108 | + // that guarantees we will get information back when the |
| 109 | + // activity is finished, no matter what happens to it. |
| 110 | + mStartedActivity = true; |
| 111 | + } |
| 112 | + |
| 113 | + cancelInputsAndStartExitTransition(options); |
| 114 | + // TODO Consider clearing/flushing other event sources and events for child windows. |
| 115 | + } else { |
| 116 | + if (options != null) { |
| 117 | + mParent.startActivityFromChild(this, intent, requestCode, options); |
| 118 | + } else { |
| 119 | + // Note we want to go through this method for compatibility with |
| 120 | + // existing applications that may have overridden it. |
| 121 | + mParent.startActivityFromChild(this, intent, requestCode); |
| 122 | + } |
| 123 | + } |
| 124 | +} |
| 125 | +``` |
| 126 | +里面调用了`mInstrumentation.execStartActivity`这是啥玩意,先看一下`mInstrumentation`属性,他是`Instrumentation`类,我们看下文档 |
| 127 | +```java |
| 128 | +/** |
| 129 | + * Base class for implementing application instrumentation code. When running |
| 130 | + * with instrumentation turned on, this class will be instantiated for you |
| 131 | + * before any of the application code, allowing you to monitor all of the |
| 132 | + * interaction the system has with the application. An Instrumentation |
| 133 | + * implementation is described to the system through an AndroidManifest.xml's |
| 134 | + * <instrumentation> tag. |
| 135 | + */ |
| 136 | +public class Instrumentation { |
| 137 | + ... |
| 138 | +} |
| 139 | +``` |
| 140 | +放狗查了下`Instrumentation`的意思是仪器、工具、装置的意思。我就大体翻一下(英语不好- -~,可能不准确)该类是实现应用程序代码的基类,当该类在 |
| 141 | +启动的状态下运行时,该类会在其他任何应用程序运行前进行初始化,允许你件事所有应用程序与系统的交互。一个`Instrumentation`实例会通过`Manifest`文件 |
| 142 | +中的`<instrumenttation`标签描述给系统。 |
| 143 | +所以继续看一下`mInstrumentation.execStartActivity()`: |
| 144 | +```java |
| 145 | +/** |
| 146 | + // 下面的注释说的很明白了默认实现会更新任何活跃的对象并分发给系统的`activity manager` |
| 147 | + * Execute a startActivity call made by the application. The default |
| 148 | + * implementation takes care of updating any active {@link ActivityMonitor} |
| 149 | + * objects and dispatches this call to the system activity manager; you can |
| 150 | + * override this to watch for the application to start an activity, and |
| 151 | + * modify what happens when it does. |
| 152 | + * |
| 153 | + * <p>This method returns an {@link ActivityResult} object, which you can |
| 154 | + * use when intercepting application calls to avoid performing the start |
| 155 | + * activity action but still return the result the application is |
| 156 | + * expecting. To do this, override this method to catch the call to start |
| 157 | + * activity so that it returns a new ActivityResult containing the results |
| 158 | + * you would like the application to see, and don't call up to the super |
| 159 | + * class. Note that an application is only expecting a result if |
| 160 | + * <var>requestCode</var> is >= 0. |
| 161 | + * |
| 162 | + * <p>This method throws {@link android.content.ActivityNotFoundException} |
| 163 | + * if there was no Activity found to run the given Intent. |
| 164 | + * |
| 165 | + * @param who The Context from which the activity is being started. |
| 166 | + * @param contextThread The main thread of the Context from which the activity |
| 167 | + * is being started. |
| 168 | + * @param token Internal token identifying to the system who is starting |
| 169 | + * the activity; may be null. |
| 170 | + * @param target Which activity is performing the start (and thus receiving |
| 171 | + * any result); may be null if this call is not being made |
| 172 | + * from an activity. |
| 173 | + * @param intent The actual Intent to start. |
| 174 | + * @param requestCode Identifier for this request's result; less than zero |
| 175 | + * if the caller is not expecting a result. |
| 176 | + * @param options Addition options. |
| 177 | + * |
| 178 | + * @return To force the return of a particular result, return an |
| 179 | + * ActivityResult object containing the desired data; otherwise |
| 180 | + * return null. The default implementation always returns null. |
| 181 | + * |
| 182 | + * @throws android.content.ActivityNotFoundException |
| 183 | + * |
| 184 | + * @see Activity#startActivity(Intent) |
| 185 | + * @see Activity#startActivityForResult(Intent, int) |
| 186 | + * @see Activity#startActivityFromChild |
| 187 | + * |
| 188 | + * {@hide} |
| 189 | + */ |
| 190 | +public ActivityResult execStartActivity( |
| 191 | + Context who, IBinder contextThread, IBinder token, Activity target, |
| 192 | + Intent intent, int requestCode, Bundle options) { |
| 193 | + IApplicationThread whoThread = (IApplicationThread) contextThread; |
| 194 | + Uri referrer = target != null ? target.onProvideReferrer() : null; |
| 195 | + if (referrer != null) { |
| 196 | + intent.putExtra(Intent.EXTRA_REFERRER, referrer); |
| 197 | + } |
| 198 | + if (mActivityMonitors != null) { |
| 199 | + synchronized (mSync) { |
| 200 | + final int N = mActivityMonitors.size(); |
| 201 | + for (int i=0; i<N; i++) { |
| 202 | + final ActivityMonitor am = mActivityMonitors.get(i); |
| 203 | + if (am.match(who, null, intent)) { |
| 204 | + am.mHits++; |
| 205 | + if (am.isBlocking()) { |
| 206 | + return requestCode >= 0 ? am.getResult() : null; |
| 207 | + } |
| 208 | + break; |
| 209 | + } |
| 210 | + } |
| 211 | + } |
| 212 | + } |
| 213 | + try { |
| 214 | + intent.migrateExtraStreamToClipData(); |
| 215 | + intent.prepareToLeaveProcess(); |
| 216 | + // 通过注释然后再结合代码一看我们就知道这应该就是分发到系统activity manager的过程 |
| 217 | + int result = ActivityManagerNative.getDefault() |
| 218 | + .startActivity(whoThread, who.getBasePackageName(), intent, |
| 219 | + intent.resolveTypeIfNeeded(who.getContentResolver()), |
| 220 | + token, target != null ? target.mEmbeddedID : null, |
| 221 | + requestCode, 0, null, options); |
| 222 | + checkStartActivityResult(result, intent); |
| 223 | + } catch (RemoteException e) { |
| 224 | + throw new RuntimeException("Failure from system", e); |
| 225 | + } |
| 226 | + return null; |
| 227 | +} |
| 228 | +``` |
| 229 | +那就直接看下`ActivityManagerNative.getDefault().startActivity()`方法,看之前我们先看看`ActivityManagerNative.getDefault()`是什么鬼: |
| 230 | +```java |
| 231 | +/** |
| 232 | + * Retrieve the system's default/global activity manager. |
| 233 | + */ |
| 234 | +static public IActivityManager getDefault() { |
| 235 | + return gDefault.get(); |
| 236 | +} |
| 237 | +``` |
| 238 | +注释说的明白的就是拿到系统默认/全局的`activity manager`,通过名字也能看出来`IActivityManager`是个接口,那就继续看`IActivityManager.startActivity()`方法吧: |
| 239 | +```java |
| 240 | +public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, |
| 241 | + String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, |
| 242 | + ProfilerInfo profilerInfo, Bundle options) throws RemoteException; |
| 243 | +``` |
| 244 | +这里就顺便看一下`IActivityManager`接口是神马鬼: |
| 245 | +``` |
| 246 | +/** |
| 247 | + * System private API for talking with the activity manager service. This |
| 248 | + * provides calls from the application back to the activity manager. |
| 249 | + * |
| 250 | + * {@hide} |
| 251 | + */ |
| 252 | +public interface IActivityManager extends IInterface { |
| 253 | + ... |
| 254 | +} |
| 255 | +``` |
| 256 | +但是看到这里我不知道怎么继续往下分析了啊,既然是接口我们要找到实现类啊,又是通过`ActivityManagerNative.getDefault()`得到的`IActivityManager`实例, |
| 257 | +所以这里我们再看下`ActivityManagerNative`类。 |
| 258 | +```java |
| 259 | +/** {@hide} */ |
| 260 | +public abstract class ActivityManagerNative extends Binder implements IActivityManager { |
| 261 | + ... |
| 262 | +} |
| 263 | +``` |
| 264 | +啊! 隐藏的,连个注释也没有,我拖动了下这个类一看`5992`行,不知道从哪下手了,还能从哪下手啊,当然是从`ActivityManagerNative.getDefault()`方法啊 |
| 265 | +```java |
| 266 | +public abstract class ActivityManagerNative extends Binder implements IActivityManager { |
| 267 | + |
| 268 | + // 继承Binder接口,而且asInterFace方法,我好想明白了点什么 |
| 269 | + /** |
| 270 | + * Cast a Binder object into an activity manager interface, generating |
| 271 | + * a proxy if needed. |
| 272 | + */ |
| 273 | + static public IActivityManager asInterface(IBinder obj) { |
| 274 | + if (obj == null) { |
| 275 | + return null; |
| 276 | + } |
| 277 | + IActivityManager in = |
| 278 | + (IActivityManager)obj.queryLocalInterface(descriptor); |
| 279 | + if (in != null) { |
| 280 | + return in; |
| 281 | + } |
| 282 | + |
| 283 | + return new ActivityManagerProxy(obj); |
| 284 | + } |
| 285 | + |
| 286 | + /** |
| 287 | + * Retrieve the system's default/global activity manager. |
| 288 | + */ |
| 289 | + static public IActivityManager getDefault() { |
| 290 | + // 使用了getDefaule的get方法 |
| 291 | + return gDefault.get(); |
| 292 | + } |
| 293 | + .... |
| 294 | +} |
| 295 | +``` |
| 296 | +继续看: |
| 297 | +```java |
| 298 | +private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { |
| 299 | + protected IActivityManager create() { |
| 300 | + // 进程间通信了 |
| 301 | + IBinder b = ServiceManager.getService("activity"); |
| 302 | + if (false) { |
| 303 | + Log.v("ActivityManager", "default service binder = " + b); |
| 304 | + } |
| 305 | + // 看到了吗?用到了刚才我们说的asInterface方法 |
| 306 | + IActivityManager am = asInterface(b); |
| 307 | + if (false) { |
| 308 | + Log.v("ActivityManager", "default service = " + am); |
| 309 | + } |
| 310 | + return am; |
| 311 | + } |
| 312 | +}; |
| 313 | +``` |
| 314 | +好了,我们再看下`asInterface()`方法: |
| 315 | +```java |
| 316 | +static public IActivityManager asInterface(IBinder obj) { |
| 317 | + if (obj == null) { |
| 318 | + return null; |
| 319 | + } |
| 320 | + IActivityManager in = |
| 321 | + (IActivityManager)obj.queryLocalInterface(descriptor); |
| 322 | + if (in != null) { |
| 323 | + return in; |
| 324 | + } |
| 325 | + // 在这里 |
| 326 | + return new ActivityManagerProxy(obj); |
| 327 | +} |
| 328 | +``` |
| 329 | +终于找到了其实就是`ActivityManagerProxy`类,刚才我们找到`IActivityManager`接口的`startActivity()` 方法,现在终于找到了在这里使用的是`IActivityManager`接口实现类的 |
| 330 | +`ActivityManagerProxy`类,我们来看一下该类实现的`startActivity()`方法: |
| 331 | +```java |
| 332 | +class ActivityManagerProxy implements IActivityManager |
| 333 | +{ |
| 334 | + public ActivityManagerProxy(IBinder remote) |
| 335 | + { |
| 336 | + mRemote = remote; |
| 337 | + } |
| 338 | + |
| 339 | + public IBinder asBinder() |
| 340 | + { |
| 341 | + return mRemote; |
| 342 | + } |
| 343 | + public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, |
| 344 | + String resolvedType, IBinder resultTo, String resultWho, int requestCode, |
| 345 | + int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException { |
| 346 | + Parcel data = Parcel.obtain(); |
| 347 | + Parcel reply = Parcel.obtain(); |
| 348 | + data.writeInterfaceToken(IActivityManager.descriptor); |
| 349 | + data.writeStrongBinder(caller != null ? caller.asBinder() : null); |
| 350 | + data.writeString(callingPackage); |
| 351 | + intent.writeToParcel(data, 0); |
| 352 | + data.writeString(resolvedType); |
| 353 | + data.writeStrongBinder(resultTo); |
| 354 | + data.writeString(resultWho); |
| 355 | + data.writeInt(requestCode); |
| 356 | + data.writeInt(startFlags); |
| 357 | + if (profilerInfo != null) { |
| 358 | + data.writeInt(1); |
| 359 | + profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); |
| 360 | + } else { |
| 361 | + data.writeInt(0); |
| 362 | + } |
| 363 | + if (options != null) { |
| 364 | + data.writeInt(1); |
| 365 | + options.writeToParcel(data, 0); |
| 366 | + } else { |
| 367 | + data.writeInt(0); |
| 368 | + } |
| 369 | + mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0); |
| 370 | + reply.readException(); |
| 371 | + int result = reply.readInt(); |
| 372 | + reply.recycle(); |
| 373 | + data.recycle(); |
| 374 | + return result; |
| 375 | + } |
| 376 | + ... |
| 377 | +} |
| 378 | +``` |
| 379 | +再继续我就不知道走到哪里了.... |
| 380 | + |
| 381 | + |
| 382 | +--- |
| 383 | + |
| 384 | +- 邮箱 :charon.chui@gmail.com |
| 385 | +- Good Luck! |
0 commit comments