Android source code analysis-Activity Startup Process

Source: Internet
Author: User

Reprinted please indicate the source: http://blog.csdn.net/singwhatiwanna/article/details/18154335

Activity is a very important concept in Android. It is the first of the four major components. There are a lot of content about Activity, such as lifecycle and startup of Flags, i'm afraid I have to write two long articles, let alone analyze their source code. However, this article does not focus on them. I want to introduce a typical startup process of an Activity. This article will analyze it from the source code perspective. We know that when startActivity is called, an Activity can be started. But do you know how this Activity is started? Every Activity is also an object. Do you know when this object was created (that is, when its constructor was called )? Why is onCreate the execution entry of the Activity? All of this is encapsulated by the system. It is transparent to us. When we use it, we only pass an intent and startActivity can achieve our goal. However, after reading this article, you will understand what is behind it. Before analysis, I will introduce several classes:

First, check the portal

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);}

Note: Obviously, from top to bottom, it is ultimately implemented by startActivityForResult.

See

Code: Activity # startActivityForResult

Public void startActivityForResult (Intent intent, int requestCode, Bundle options) {// The mParent of a general Activity is null. mParent is often used in ActivityGroup. if (mParent = null) has been discarded by ActivityGroup) {// a new Activity will be started here, and the core functions are all in mMainThread. the Instrumentation is completed in getApplicationThread. activityResult ar variable minstrumentation.exe cStartActivity (this, mMainThread. getApplicationThread (), mToken, this, intent, requestCode, options); if (ar! = Null) {// sending result, that is, onActivityResult will be called 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 already ed. 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 {// when the Activity in the ActivityGroup calls startActivity, the internal processing logic is similar to the above 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 );}}}

Note: The key points of the above Code have been commented out. You can find that the implementation of truly opening the activity is in the execStartActivity method of Instrumentation. Go and have a look.

Code: Instrumentation # execStartActivity

Public ActivityResult execStartActivity (Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {// core functions are completed in this whoThread, the internal scheduleLaunchActivity method is used to open IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors! = Null) {synchronized (mSync) {// check whether the activityfinal int N = mActivityMonitors exists. size (); for (int I = 0; I <N; I ++) {final ActivityMonitor am = mActivityMonitors. get (I); if (am. match (who, null, intent) {// if found, it jumps out of the loop am. mHits ++; // if the target activity cannot be opened, returnif (am. isBlocking () {return requestCode> = 0? Am. getResult (): null;} break ;}}try {intent. migrateExtraStreamToClipData (); intent. prepareToLeaveProcess (); // This is where the activity is actually opened, and the core functions are completed in 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); // This method throws an exception and checks the result. If activity cannot be opened, // throw various exceptions such as ActivityNotFoundException checkStartActivityResult (result, intent);} catch (RemoteException e) {} return null ;}

Note: I would like to talk about this method checkStartActivityResult. It is also specialized in throwing exceptions and reading the code. I believe everyone is familiar with the exception information below, among them, the most familiar non-Unable to find explicit activity class does not belong. If you do not register the target activity in xml, this exception will be thrown.

    /*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);        }    }

Next, let's take a look at IApplicationThread, because the core function is completed by its internal scheduleLaunchActivity method. Because IApplicationThread is an interface, we need to find its implementation class, I have already found it for you. It is the internal class ApplicationThread in ActivityThread. Let's take a look at its inheritance relationship:

Private class ApplicationThread extends ApplicationThreadNative;

Public abstract class ApplicationThreadNative extends Binder implements IApplicationThread;

We can see that ApplicationThread has indirectly implemented the IApplicationThread interface. First, let's look at the structure of this class.

After reading the general structure of ApplicationThread, we should be able to guess that the resume, newIntent, pause, stop and other events in the Activity life cycle are triggered by it. In fact, this is indeed the case. Here, we only look at the scheduleLaunchActivity method to illustrate the problem.

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);}

Note: The code above is easy to understand. Construct an activity record and then send a message. So, let's take a look at how Handler processes the message. Now we can go to this Handler, it has a very short name called H.

Code: ActivityThread # H

// This class is too long. I only post the private class H extends Handler {public void handleMessage (Message msg) {if (DEBUG_MESSAGES) Slog. v (TAG, ">>> handling:" + codeToString (msg. what); switch (msg. what) {// handle LAUNCH_ACTIVITY Message Type here case LAUNCH_ACTIVITY: {Trace. traceBegin (Trace. TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); ActivityClientRecord r = (ActivityClientRecord) msg. obj; r. packageInfo = getPackageInfoNoCheck (r. act IvityInfo. applicationInfo, r. compatInfo); // process the startActivity message 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_ACTIVIT Y: 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 ;...}}

Notes: 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); // Finally, everyone is a little impatient. We can see from the method name that, // when mlaunchactivity is called, the activity is instantiated and onCreate is called activity a = perf. OrmLaunchActivity (r, customIntent); if (! = Null) {r. createdConfig = new Configuration (mConfiguration); Bundle oldState = r. state; // No. The onResume of the target activity is called 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 failed CT 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; // At the same time, because the new activity is called, The onPause of the original activity will be called 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 (). tow.string () + ":" + 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 }}}

Note: The Status synchronization between the original activity and the new activity can be studied by yourself if you are interested. Because the logic is too complex, I cannot clarify all the problems, otherwise, it would be too detailed to overwhelm the overall logic. To study the source code, we need to understand the overall logic. Next, let's take a look at the last method, which is the real implementation of the activity startup process.
Code: ActivityThread # initialize mlaunchactivity

Private Activity initialize mlaunchactivity (ActivityClientRecord r, Intent customIntent) {// System. out. println ("##### [" + System. currentTimeMillis () + "] ActivityThread. extends mlaunchactivity ("+ r +") "); ActivityInfo aInfo = r. activityInfo; if (r. packageInfo = null) {r. packageInfo = getPackageInfo (aInfo. applicationInfo, r. compatInfo, Context. CONTEXT_INCLUDE_CODE);} // parse the start parameter Componen of the target activity from the intent. TName component = r. intent. getComponent (); if (component = null) {component = r. intent. resolveActivity (mInitialApplication. getPackageManager (); r. intent. setComponent (component);} if (r.activityInfo.tar getActivity! = Null) {component = new ComponentName(r.activityInfo.packageName,r.activityInfo.tar getActivity);} Activity activity = null; try {java. lang. classLoader cl = r. packageInfo. getClassLoader (); // use ClassLoader (Class Loader) load the class of the target activity through the class name and call newInstance to instantiate an object // In fact, a new object is created through the no-argument constructor of the Activity, the object is new here. 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, "launch Ming launch of" + r); if (localLOGV) Slog. v (TAG, r + ": app =" + app + ", appName =" + app. getPackageName () + ", pkg =" + r. packageInfo. getPackageName () + ", Comp =" + r. intent. getComponent (). tow.string () + ", 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; // onCreate of the target activity is called. So far, the Activity is started, and the following process is the lifecycle of the Activity. // As mentioned earlier in this article, the mInstrumentation is completed internally by ApplicationThread during various statuses of its lifecycle. 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. initialize mstart (); 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 ;}

I believe that when you see this, you should have a perceptual knowledge of the Activity startup process. The Activity is complex and has many features. This article does not provide in-depth analysis on all details. Even if you have analyzed all the details, how long does the article take, are you still patient? I hope this article will help you. Thank you for reading this article.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.