Exploration of Activity Startup Process in Android
Android. app. ActivityThread. javasmlaunchactivity () The following is part of the source code, which I have omitted. Copy code 1 private Activity extends mlaunchactivity (ActivityClientRecord r, Intent customIntent) {2 3... 4 Activity activity = null; 5 try {6 java. lang. classLoader cl = r. packageInfo. getClassLoader (); 7 activity = mInstrumentation. newActivity (8 cl, component. getClassName (), r. intent); 9 StrictMode. incrementExpectedActivityCount (activity. getClass (); 10 r. intent. setExtrasClassLoader (cl); 11 if (r. state! = Null) {12 r. state. setClassLoader (cl); 13} 14} catch (Exception e) {15 if (! MInstrumentation. onException (activity, e) {16 throw new RuntimeException (17 "Unable to instantiate activity" + component18 + ":" + e. toString (), e); 19} 20} 21 22 try {23... 24 if (activity! = Null) {25... 26 27 activity. attach (appContext, this, getInstrumentation (), r. token, 28 r. ident, app, r. intent, r. activityInfo, title, r. parent, 29 r. embeddedID, r. lastNonConfigurationInstances, config); 30... 31 activity. mCalled = false; 32 mInstrumentation. callActivityOnCreate (activity, r. state); 33... 34} 35... 36} 37... 38} copy the code to focus on the bold red part: Lines 7 and 8: Build an Activity object using the Activity class name. Row 27: The Activity. attach () method is called. Row 32: Execute the onCreate () method of the Activity through the Instrumentation object. The life cycle method of the Activity is called by the Instrumentation object. The attach () method is also very important. Android. app. activity. attach () Copy code 1 final void attach (Context context, ActivityThread aThread, 2 Instrumentation instr, IBinder token, int ident, 3 Application application, Intent intent, ActivityInfo info, 4 CharSequence title, activity parent, String id, 5 NonConfigurationInstances lastNonConfigurationInstances, 6 Configuration config) {7 attachBaseContext (context); 8 9 mFragments. attachActivi Ty (this, mContainer, null); 10 11 mWindow = PolicyManager. makeNewWindow (this); 12 13... // assign various parameters to the Activity member variable 14 15 mWindow. setWindowManager (16 (WindowManager) context. getSystemService (Context. WINDOW_SERVICE), 17 mToken, mComponent. flattenToString (), 18 (info. flags & ActivityInfo. FLAG_HARDWARE_ACCELERATED )! = 0); 19 if (mParent! = Null) {20 mWindow. setContainer (mParent. getWindow (); 21} 22 mWindowManager = mWindow. getWindowManager (); 23 mCurrentConfig = config; 24} copy the code to the Activity first. assign values to mWindow member variables, set WindowManager for mWindow variables, and then assign values to Activity. mWindowManager assignment. MWindow is a variable of the Window type, but it is actually a PhoneWindow object, which is related to the display of Activity content. After the attach () method is called, The onCreate () method of the Activity is called. In general, the onCreate () method in the Activity calls the setContentView () method, while the setContentView () method is not implemented by the Activity. The following are android. app. code in the Activity: 1 public void setContentView (View view, ViewGroup. layoutParams params) {2 getWindow (). setContentView (view, params); 3 initActionBar (); 4} while getWindow () returns an android. app. window object, which is the mWindow member variable assigned in attach. Android. app. Window is an abstract class. The setContentView () method is not implemented in detail, and the true implementation of this method is the com. android. internal. policy. impl. PhoneWindow class. Use a class diagram: The following is the setContentView () code in PhoneWindow. Copy code 1 @ Override 2 public void setContentView (View view, ViewGroup. layoutParams params) {3 if (mContentParent = null) {4 installDecor (); 5} else {6 mContentParent. removeAllViews (); 7} 8 mContentParent. addView (view, params); 9 final Callback cb = getCallback (); 10 if (cb! = Null &&! IsDestroyed () {11 cb. onContentChanged (); 12} 13} the copy code PhoneWindow class contains two view-related member variables: DecorView mDecor and ViewGroup mContentParent. Let's take a look at the description in the official document: Return to the installDecor () method in PhoneWindow. setContentView (View, ViewGroup. LayoutParams. Copy code 1 private void installDecor () {2 if (mDecor = null) {3 mDecor = generateDecor (); 4... 5} 6 if (mContentParent = null) {7 mContentParent = generateLayout (mDecor); 8... 9} 10} copy the code mDecor through a generateDecor () method. GenerateDecor () is a new DecorView. 1 protected DecorView generateDecor () {2 return new DecorView (getContext (),-1); 3} DecorView is an internal class defined in the PhoneWindow class, which inherits FrameLayout, used as the root view of the entire PhoneWindow. Let's take a look at what generateLayout () has done. Copy the Code 1 protected ViewGroup generateLayout (DecorView decor) {2 3 //... save the preceding steps. In general, the view settings are related to the style, topic, and version. 4 5 // enter decor 6 7 // Inflate the window decor. 8 int layoutResource; // This is id 9 10 for inflate... // This is omitted. The content is to assign a proper view id to layoutResource11 12 mDecor Based on the feature of the Window. startChanging (); 13 14 View in = mLayoutInflater. inflate (layoutResource, null); 15 decor. addView (in, new ViewGroup. layoutParams (MATCH_PARENT, MATCH_PARENT); 16 17 ViewGroup contentParent = (ViewGroup) findViewById (ID_ANDROID_CONTEN T); // note that 18 if (contentParent = null) {19 throw new RuntimeException ("Window couldn't find content container view "); 20} 21 22... // save, the content is to set the background and set some attributes of the ActionBar. 23 24 mDecor. finishChanging (); 25 26 return contentParent; 27} the copied Code shows that this method (generateLayout () has done the following key tasks: 1. the LayoutParam parameter is set based on various FLAG values. The above Code ignores this part. 2. According to various FEATURE values, a suitable layout id similar to R. layout. something is assigned to layoutResource. 3. Fill in layoutResource as a View object and add it to DecorView. 4. [uncertain, I guess] There is a ViewGroup object with id ID_ANDROID_CONTENT in the layout file indicated by layoutResource. In the above Code, the ViewGroup is obtained by the findViewById with "very confident" source code. 5. Finally, return the contentParent to the mContentParent member variable of PhoneWindow. In this way, we know the origins of the member variables mDecor and mContentParent. In the course of learning, I also learned that mDecor manages an ActionBar. Based on the above research, we also have some thoughts and guesses. Make a small Summary of PhoneWindow: 1. an Activity corresponds to A PhoneWindow object, which is A one-to-one relationship. If Activity A starts to Activity B, Activity B creates its own PhoneWindow object. 2. PhoneWindow manages the content of the entire screen, excluding the system status bar at the top of the screen. Therefore, PhoneWindow or Window is associated with a page of the application. 3. phoneWindow manages the ActionBar and the following content topics at the same time. The setContentView () method is used to set the content subject, and other methods such as setTitle () are used to operate the ActionBar, the requestFeature () method defined in Window has many settings related to the ActionBar attribute. In addition, these methods are all public methods, which are obviously called for client programmers and further prove the significance and role of these operations. 4. phoneWindow itself is not a View. Its member variable mDecor is the View of the entire interface. mDecor is filled out during generateLayout, the actionBar and contentParent views are obtained directly from mDecor through findViewById. As mentioned above, the installDector () method is only executed. Next is mContentParent. removeAllViews (). This is easy to understand. If setContentView () is called twice, the content must be cleared and removed for the second time. After removal, add mContentParent. addView (view, params ). This method is a method in ViewGroup, and the source code is pasted: requestLayout () is called first. This method does not actually work here. ViewGourp. requestLayout () is actually the called View. requestLayout () method, while View. in the requestLayout () method, except for some View operations, the requestLayout () method of the mParent member variable in the View is actually called, the member variable mParent is a ViewParent object, and ViewParent is an interface, and the mParent object in View is through View. the assignParent (ViewParent) method is used to assign values, while the assignParent () method is composed of ViewRootImpl. setView () method call ...... I will not consider it for the time being. It should be clear that requestLayout () does not play a specific role. Next, observe the addViewInner () method. This method is to add child to its own View array and save it. Then, mark the child's parent as itself. So far, the setContentView () method has basically been executed. At this time, the interface has not yet shown as "he Dongxi", rather than "customer layout) A tree structure is built. Assume that the setContentView () method is the only method called in the onCreate () method, the onCreate () method is also executed, and the call stack continues to roll back, and then returns to android. app. activityThread. in handleLaunchActivity (), the above is just execution of android. app. activityThread. initialize mlaunchactivity (). Next, execute the second key method handleResumeActivity (). Android. app. activityThread. handleResumeActivity (): Copy code 1 final void handleResumeActivity (IBinder token, boolean clearHide, boolean isForward, 2 boolean reallyResume) {3... 4 5 ActivityClientRecord r = extends mresumeactivity (token, clearHide); 6 7 if (r! = Null) {8 final Activity a = r. activity; 9... 10 if (r. window = null &&! A. mFinished & willBeVisible) {11 r. window = r. activity. getWindow (); 12 View decor = r. window. getDecorView (); 13 decor. setVisibility (View. INVISIBLE); 14 ViewManager wm =. getWindowManager (); 15 WindowManager. layoutParams l = r. window. getAttributes (); 16. mDecor = decor; 17 l. type = WindowManager. layoutParams. TYPE_BASE_APPLICATION; 18 l. softInputMode | = forwardBit; 19 if (. mVisibleFromClient) {20. mWind OwAdded = true; 21 wm. addView (decor, l); 22} 23... 24} 25... 26} 27} copy the code to pay attention to the bold red part: first, the invoke mresumeactivity () method. In this method, the onResume () method of Activity is called through Instrumentation. The following wm. the addView () method is critical, and wm is the above. getWindowManager () obtains the mWindowManger object returned by Activity and getWindowManager (), which is WindowManagerImpl. Most of its internal methods are WindowManagerGlobal of the proxy, this is already mentioned in the above content. However, what is the addView () of WindowManger? Copy code 1 public void addView (View view, ViewGroup. layoutParams params, 2 Display display, Window parentWindow) {3... 4 ViewRootImpl root; 5 View panelParentView = null; 6 7... 8 root = new ViewRootImpl (view. getContext (), display); 9 10 view. setLayoutParams (wparams); 11 12 mViews. add (view); 13 mRoots. add (root); 14 mParams. add (wparams); 15} 16 17 // do this last because it fires off messages to start d Oing things18 try {19 root. setView (view, wparams, panelParentView); 20} catch (RuntimeException e) {21... 22 throw e; 23} 24} copy the code. From the code above, we can see that in the addView method, a new ViewRootImpl object is added, and then ViewRootImpl is called. setView () method. Android. view. viewRootImpl. setView () Copy code 1/** 2 * We have one child 3 */4 public void setView (View view, WindowManager. layoutParams attrs, View panelParentView) {5 synchronized (this) {6 if (mView = null) {7 mView = view; 8... 9 10 // Schedule the first layout-before-adding to the window11 // manager, to make sure we do the relayout before paiing12 // any other events from the system.1 3 requestLayout (); 14 15... 16 17 view. assignParent (this); 18... 19} 20} 21} copy the Code omitted from the code as shown above. First, assign the passed parameter view to mView. Here, we need to make it clear that ViewRootImpl is not a subclass of the View ...... Therefore, I think mView will be the root node recognized by this object and the root node of the entire Activity. Next, the requestLayout () method is called. This method is valid! Finally, register the parent of view as himself. Finally, mDecor knows who his father is, or the whole Activity sets a root node. Before that, we setContentView () add our layout to PhoneWindow. when mContentParent is used, mDecor does not know which parent it is. Now the root node is included in the tree structure of the view, that is, ViewRootImpl. Therefore, requestLayout () is effective, you can perform the following three steps: measure, layout, and draw. Android. view. ViewRootImpl. requestLayout () This method first checks whether it is in the main thread, and then executes the scheduleTraversals () method. Based on the method name, we can see that the traversal is performed once, And the traversal object is the view tree starting from the root node. Android. view. ViewRootImpl. scheduleTraversals () Pay attention to the marked Runnable object. The doTraversal () method is called in the Runnable run () method. The doTraversal () method calls the receivmtraversals () method. This method is very long. In turn, it calls the three methods: descrimmeasure (), descrimlayout (), and descrimdraw, finally, we started the measurement, layout, and drawing of the control layer. I will leave these explorations to the next blog. This article is long enough. Conclusion: It took two days to view the source code on grepcode. I still feel a little bit rewarding. I learned something I never knew before. The biggest feeling is that as long as the source code is complete, you can still figure it out. In addition, the relationship between these contents and actual applications remains to be further explored and accumulated experience.