View ing timing analysis, view ing timing
This is really a good piece of text. I am racking my brains and hope to help the readers! Because there are almost no articles starting with view ing on the Internet, and you need to have a deep understanding of the process of starting activity and drawing view if you are looking for it yourself, so I think developers who have worked for three years may not be able to get to this point. Start the text below.
The timing of drawing a view has always been confusing in my mind. Where did it start? Why can I get the width and height of a view only in ondomainswfocuschanged?
The reason is that onCreate, onStart, and onResume have not started the view ing. There are too many misleading information on the Internet, so I have ignored this point all the time. In fact, if the view is being mapped, why can't we get the view parameters?
Finally, I was inspired by this section in the Window creation process of the Activity for art development. In three steps, check whether the decorview exists. If it does not exist, we need to create a decorview; in addition, we add the root layout to the decor view. Finally, we add the decorview to the phone window.
At this time, I began to think about it. Our root layout was added to the decor view, is a ing performed before being added to the decor view or a ing started after being added to the decor view?
Soon I came up with the answer. Why? Because I am familiar with the custom view process, in measure, the most important task we do is to get the measurement spec of the sub-view from the parent container information + layout params --> of the sub-view. The parent container information here refers to two types: If you are decorview, the parent container information is phonewindow; if you are not decorview, then the information of this parent container is measure spec.
This is why we cannot perform a ing before adding decorview to phonewindow. Because decorview requires the phonewindow information, the sub-view of decorview requires the measure spec of the parent view group, layout draw is based on measure, so we can draw this conclusion quickly.
The above is my idea. Next I will take the idea to see the source code. We only need to find the code in the form of window. add (decor. Where can I start searching? This requires a deep understanding of the activity startup process. Starting from startActivity, I skipped some steps and finally found that it will be called here
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global and // override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
App. thread is the internal class of ApplicationThread and ActivityThread.
ApplicationThread. scheduleLaunchActivity, which sends a message
sendMessage(H.LAUNCH_ACTIVITY, r);
The message processor is also the internal class of ActivityThread, H, inherited from Handler
Take a look
public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case LAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); final ActivityClientRecord r = (ActivityClientRecord) msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break;
Here, handleLaunchActivity is the place where the lifecycle of the activity is officially started. onCreate, onStart, and onResume will be completed here. The method representing onResume is handleResumeActivity, which will be called in handleResumeActivity:
r.activity.makeVisible();
Let's take a look at Activity. makeVisible.
void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE);}
The conclusion is drawn. In the resume process, decor --> add to --> window manager is performed. Now we can start to trace the start time of view painting!
In the addView method of window manager impl, we can finally see the instantiation of ViewRootImpl object, and? ? View root impl object where decorview starts operations
root = new ViewRootImpl(view.getContext(), display);
root.setView(view, wparams, panelParentView);
In the setView method
// Schedule the first layout -before- adding to the window// manager, to make sure we do the relayout before receiving// any other events from the system.requestLayout();
I met our familiar friend and the above comments proved this point.
RequestLayout
@Overridepublic void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); }}
ScheduleTraversals
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); }}
The postCallback here is very important. There is an mTraversalRunnable in it. You can undoubtedly find out that postCallback will eventually call the run method of the mTraversalRunnable. We only need to find the mTraversalRunnable.
final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); }}
DoTraversal
void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor"); } performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false; } }}
Finally, I saw my dear mongomtraversals. At this point, the source code has been traced back.
Looking back at this string, we don't need to remember it. Because our starting point is to prove that when resume, we will add decor view to the window and then start the painting process. Now we have undoubtedly achieved our goal. That is to say, the above source code tracing process can be ignored. You only need to remember the conclusion we have analyzed!
Finally, let's talk about the problem I encountered when I was in the United States. What is the difference between addView and Direct Writing in layout? (In fact, this problem is one of the reasons that prompted me to write this article ). At that time, I did not answer well. Then Baidu has nothing to do with it. I just heard a bunch of foreigners say, Wow, this will trigger requestlayouttwice. oh my god, this is too bad! I believe it. Today, neither is nor. Let's look at the code we are most familiar :?
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
SetContentView can also be written as follows:
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null, false); setContentView(view);
What if addView is added?
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewGroup view = (ViewGroup) LayoutInflater.from(this).inflate(R.layout.activity_main, null, false); view.addView(new TextView(this)); setContentView(view);
Do you think it is different from writing in layout files? We use xmlParser to obtain the name of the String type of the object in the layout file, get the Class object according to the full path name, and then create the entire view tree. It is no different from our dynamic addView! Because we do not perform view ing until resume.
The only difference is that the addView has better performance and has to go through the process of xml parsing and reflection creation in the layout file. The performance is 3-5 times different, but it is only a view, I think this gap is better than none.