1. 程式人生 > >Android原始碼分析-Activity的啟動過程

Android原始碼分析-Activity的啟動過程

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                轉載請註明出處: http://blog.csdn.net/singwhatiwanna/article/details/18154335

前言

Activity是Android中一個很重要的概念,堪稱四大元件之首,關於Activity有很多內容,比如生命週期和啟動Flags,這二者想要說清楚,恐怕又要寫兩篇長文,更何況分析它們的原始碼呢。不過本文的側重點不是它們,我要介紹的是一個Activity典型的啟動過程,本文會從原始碼的角度對其進行分析。我們知道,當startActivity被呼叫的時候,可以啟動一個Activity,但是你知道這個Activity是如何被啟動的嗎?每個Activity也是一個物件,你知道這個物件是啥時候被建立的嗎(也就是說它的構造方法是什麼時候被呼叫的)?為什麼onCreate是Activity的執行入口?所有的這一切都被系統封裝好了,對我們來說是透明的,我們使用的時候僅僅是傳遞一個intent然後startActivity就可以達到目的了,不過,閱讀了本文以後,你將會了解它的背後到底做了哪些事情。在分析之前,我先介紹幾個類:

  1. Activity:這個大家都熟悉,startActivity方法的真正實現在Activity中
  2. Instrumentation:用來輔助Activity完成啟動Activity的過程
  3. ActivityThread(包含ApplicationThread + ApplicationThreadNative + IApplicationThread):真正啟動Activity的實現都在這裡

原始碼分析

首先看入口

code:Activity#startActivity

@Overridepublic void startActivity(Intent intent)
{ startActivity(intent, null);}@Overridepublic void startActivity(Intent intent, 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); }}public void startActivityForResult(Intent intent, int requestCode) { startActivityForResult(intent, requestCode, null);}

說明:顯然,從上往下,最終都是由startActivityForResult來實現的

接著看

code:Activity#startActivityForResult

public void startActivityForResult(Intent intent, int requestCode, Bundle options) //一般的Activity其mParent為null,mParent常用在ActivityGroup中,ActivityGroup已廢棄 if (mParent == null) {  //這裡會啟動新的Activity,核心功能都在mMainThread.getApplicationThread()中完成  Instrumentation.ActivityResult ar =   mInstrumentation.execStartActivity(    this, mMainThread.getApplicationThread(), mToken, this,    intent, requestCode, options);  if (ar != null) {      //傳送結果,即onActivityResult會被呼叫   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;  }  final View decor = mWindow != null ? mWindow.peekDecorView() : null;  if (decor != null) {   decor.cancelPendingInputEvents();  }  // TODO Consider clearing/flushing other event sources and events for child windows. } else {  //在ActivityGroup內部的Activity呼叫startActivity的時候會走到這裡,內部處理邏輯和上面是類似的  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);  } }}

說明:上述程式碼關鍵點都有註釋了,可以發現,真正開啟activity的實現在Instrumentation的execStartActivity方法中,去看看

code:Instrumentation#execStartActivity

public ActivityResult execStartActivity(  Context who, IBinder contextThread, IBinder token, Activity target,  Intent intent, int requestCode, Bundle options) //核心功能在這個whoThread中完成,其內部scheduleLaunchActivity方法用於完成activity的開啟 IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) {  synchronized (mSync) {   //先查詢一遍看是否存在這個activity   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++;     //如果目標activity無法開啟,直接return     if (am.isBlocking()) {      return requestCode >= 0 ? am.getResult() : null;     }     break;    }   }  } } try {  intent.migrateExtraStreamToClipData();  intent.prepareToLeaveProcess();  //這裡才是真正開啟activity的地方,核心功能在whoThread中完成。  int result = ActivityManagerNative.getDefault()   .startActivity(whoThread, who.getBasePackageName(), intent,     intent.resolveTypeIfNeeded(who.getContentResolver()),     token, target != null ? target.mEmbeddedID : null,     requestCode, 0, null, null, options);  //這個方法是專門拋異常的,它會對結果進行檢查,如果無法開啟activity,  //則丟擲諸如ActivityNotFoundException類似的各種異常  checkStartActivityResult(result, intent); } catch (RemoteException e) { } return null;}

說明:我想再說一下這個方法checkStartActivityResult,它也專業拋異常的,看程式碼,相信大家對下面的異常資訊不陌生吧,就是它乾的,其中最熟悉的非Unable to find explicit activity class莫屬了,如果你在xml中沒有註冊目標activity,此異常將會丟擲。

    /*package*/ static void checkStartActivityResult(int res, Object intent) {        if (res >= ActivityManager.START_SUCCESS) {            return;        }                switch (res) {            case ActivityManager.START_INTENT_NOT_RESOLVED:            case ActivityManager.START_CLASS_NOT_FOUND:                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)                    throw new ActivityNotFoundException(                            "Unable to find explicit activity class "                            + ((Intent)intent).getComponent().toShortString()                            + "; have you declared this activity in your AndroidManifest.xml?");                throw new ActivityNotFoundException(                        "No Activity found to handle " + intent);            case ActivityManager.START_PERMISSION_DENIED:                throw new SecurityException("Not allowed to start activity "                        + intent);            case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:                throw new AndroidRuntimeException(                        "FORWARD_RESULT_FLAG used while also requesting a result");            case ActivityManager.START_NOT_ACTIVITY:                throw new IllegalArgumentException(                        "PendingIntent is not an activity");            default:                throw new AndroidRuntimeException("Unknown error code "                        + res + " when starting " + intent);        }    }

接下來我們要去看看IApplicationThread,因為核心功能由其內部的scheduleLaunchActivity方法來完成,由於IApplicationThread是個介面,所以,我們需要找到它的實現類,我已經幫大家找到了,它就是ActivityThread中的內部類ApplicationThread,看下它的繼承關係:

private class ApplicationThread extends ApplicationThreadNative;

public abstract class ApplicationThreadNative extends Binder implements IApplicationThread;

可以發現,ApplicationThread還是間接實現了IApplicationThread介面,先看下這個類的結構

看完ApplicationThread的大致結構,我們應該能夠猜測到,Activity的生命週期中的resume、newIntent、pause、stop等事件都是由它觸發的,事實上,的確是這樣的。這裡,我們為了說明問題,僅僅看scheduleLaunchActivity方法

code:ApplicationThread#scheduleLaunchActivity

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,  ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,  int procState, Bundle state, List<ResultInfo> pendingResults,  List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,  String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { updateProcessState(procState, false); ActivityClientRecord r = new ActivityClientRecord(); r.token = token; r.ident = ident; r.intent = intent; r.activityInfo = info; r.compatInfo = compatInfo; r.state = state; r.pendingResults = pendingResults; r.pendingIntents = pendingNewIntents; r.startsNotResumed = notResumed; r.isForward = isForward; r.profileFile = profileName; r.profileFd = profileFd; r.autoStopProfiler = autoStopProfiler; updatePendingConfiguration(curConfig); queueOrSendMessage(H.LAUNCH_ACTIVITY, r);}

說明:上述程式碼很好理解,構造一個activity記錄,然後傳送一個訊息,所以,我們要看看Handler是如何處理這個訊息的,現在轉到這個Handler,它有個很短的名字叫做H

code:ActivityThread#H

//這個類太長,我只帖出了我們用到的部分private class H extends Handler public void handleMessage(Message msg) {  if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));  switch (msg.what) {   //這裡處理LAUNCH_ACTIVITY訊息型別   case LAUNCH_ACTIVITY: {    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");    ActivityClientRecord r = (ActivityClientRecord)msg.obj;    r.packageInfo = getPackageInfoNoCheck(      r.activityInfo.applicationInfo, r.compatInfo);    //這裡處理startActivity訊息    handleLaunchActivity(r, null);    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);   } break;   case RELAUNCH_ACTIVITY: {    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");    ActivityClientRecord r = (ActivityClientRecord)msg.obj;    handleRelaunchActivity(r);    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);   } break;   case PAUSE_ACTIVITY:    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");    handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);    maybeSnapshot();    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    break;   ...  }}

說明:看來還要看handleLaunchActivity

code:ActivityThread#handleLaunchActivity

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); if (r.profileFd != null) {  mProfiler.setProfiler(r.profileFile, r.profileFd);  mProfiler.startProfiling();  mProfiler.autoStopProfiler = r.autoStopProfiler; } // Make sure we are running with the most recent config. handleConfigurationChanged(null, null); if (localLOGV) Slog.v(  TAG, "Handling launch of " + r); //終於到底了,大家都有點不耐煩了吧,從方法名可以看出, //performLaunchActivity真正完成了activity的調起, //同時activity會被例項化,並且onCreate會被呼叫 Activity a = performLaunchActivity(r, customIntent); if (a != null) {  r.createdConfig = new Configuration(mConfiguration);  Bundle oldState = r.state;  //看到沒,目標activity的onResume會被呼叫  handleResumeActivity(r.token, false, r.isForward,    !r.activity.mFinished && !r.startsNotResumed);  if (!r.activity.mFinished && r.startsNotResumed) {   // The activity manager actually wants this one to start out   // paused, because it needs to be visible but isn't in the   // foreground.  We accomplish this by going through the   // normal startup (because activities expect to go through   // onResume() the first time they run, before their window   // is displayed), and then pausing it.  However, in this case   // we do -not- need to do the full pause cycle (of freezing   // and such) because the activity manager assumes it can just   // retain the current state it has.   try {    r.activity.mCalled = false;    //同時,由於新activity被調起了,原activity的onPause會被呼叫    mInstrumentation.callActivityOnPause(r.activity);    // We need to keep around the original state, in case    // we need to be created again.  But we only do this    // for pre-Honeycomb apps, which always save their state    // when pausing, so we can not have them save their state    // when restarting from a paused state.  For HC and later,    // we want to (and can) let the state be saved as the normal    // part of stopping the activity.    if (r.isPreHoneycomb()) {     r.state = oldState;    }    if (!r.activity.mCalled) {     throw new SuperNotCalledException(      "Activity " + r.intent.getComponent().toShortString() +      " did not call through to super.onPause()");    }   } catch (SuperNotCalledException e) {    throw e;   } catch (Exception e) {    if (!mInstrumentation.onException(r.activity, e)) {     throw new RuntimeException(       "Unable to pause activity "       + r.intent.getComponent().toShortString()       + ": " + e.toString(), e);    }   }   r.paused = true;  } } else {  // If there was an error, for any reason, tell the activity  // manager to stop us.  try {   ActivityManagerNative.getDefault()    .finishActivity(r.token, Activity.RESULT_CANCELED, null);  } catch (RemoteException ex) {   // Ignore  } }}

說明:關於原activity和新activity之間的狀態同步,如果大家感興趣可以自己研究下,因為邏輯太複雜,我沒法把所有問題都說清楚,否則就太深入細節而淹沒了整體邏輯,研究原始碼要的就是清楚整體邏輯。下面看最後一個方法,這個方法是activity的啟動過程的真正實現。
code:ActivityThread#performLaunchActivity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) {  r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,    Context.CONTEXT_INCLUDE_CODE); } //首先從intent中解析出目標activity的啟動引數 ComponentName component = r.intent.getComponent(); if (component == null) {  component = r.intent.resolveActivity(   mInitialApplication.getPackageManager());  r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) {  component = new ComponentName(r.activityInfo.packageName,    r.activityInfo.targetActivity); } Activity activity = nulltry {  java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  //用ClassLoader(類載入器)將目標activity的類通過類名載入進來並呼叫newInstance來例項化一個物件  //其實就是通過Activity的無參構造方法來new一個物件,物件就是在這裡new出來的。  activity = mInstrumentation.newActivity(    cl, component.getClassName(), r.intent);  StrictMode.incrementExpectedActivityCount(activity.getClass());  r.intent.setExtrasClassLoader(cl);  if (r.state != null) {   r.state.setClassLoader(cl);  } } catch (Exception e) {  if (!mInstrumentation.onException(activity, e)) {   throw new RuntimeException(    "Unable to instantiate activity " + component    + ": " + e.toString(), e);  } } try {  Application app = r.packageInfo.makeApplication(false, mInstrumentation);  if (localLOGV) Slog.v(TAG, "Performing launch of " + r);  if (localLOGV) Slog.v(    TAG, r + ": app=" + app    + ", appName=" + app.getPackageName()    + ", pkg=" + r.packageInfo.getPackageName()    + ", comp=" + r.intent.getComponent().toShortString()    + ", dir=" + r.packageInfo.getAppDir());  if (activity != null) {   Context appContext = createBaseContextForActivity(r, activity);   CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());   Configuration config = new Configuration(mCompatConfiguration);   if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "     + r.activityInfo.name + " with config " + config);   activity.attach(appContext, this, getInstrumentation(), r.token,     r.ident, app, r.intent, r.activityInfo, title, r.parent,     r.embeddedID, r.lastNonConfigurationInstances, config);   if (customIntent != null) {    activity.mIntent = customIntent;   }   r.lastNonConfigurationInstances = null;   activity.mStartedActivity = false;   int theme = r.activityInfo.getThemeResource()   if (theme != 0) {    activity.setTheme(theme);   }   activity.mCalled = false;   //目標activity的onCreate被呼叫了,到此為止,Activity被啟動了,接下來的流程就是Activity的生命週期了,   //本文之前已經提到,其生命週期的各種狀態的切換由ApplicationThread內部來完成   mInstrumentation.callActivityOnCreate(activity, r.state);   if (!activity.mCalled) {    throw new SuperNotCalledException(     "Activity " + r.intent.getComponent().toShortString() +     " did not call through to super.onCreate()");   }   r.activity = activity;   r.stopped = true;   if (!r.activity.mFinished) {    activity.performStart();    r.stopped = false;   }   if (!r.activity.mFinished) {    if (r.state != null) {     mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);    }   }   if (!r.activity.mFinished) {    activity.mCalled = false;    mInstrumentation.callActivityOnPostCreate(activity, r.state);    if (!activity.mCalled) {     throw new SuperNotCalledException(      "Activity " + r.intent.getComponent().toShortString() +      " did not call through to super.onPostCreate()");    }   }  }  r.paused = true;  mActivities.put(r.token, r); } catch (SuperNotCalledException e) {  throw e; } catch (Exception e) {  if (!mInstrumentation.onException(activity, e)) {   throw new RuntimeException(    "Unable to start activity " + component    + ": " + e.toString(), e);  } } return activity;}

總結

相信當你看到這裡的時候,你對Activity的啟動過程應該有了一個感性的認識。Activity很複雜,特性很多,本文沒法對各個細節進行深入分析,而且就算真的對各個細節都進行了深入分析,那文章要有多長啊,還有人有耐心看下去嗎?希望本文能夠給大家帶來一些幫助,謝謝大家閱讀。 

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述