What do you got?

Here’s what you can get from the article:

  • So what happens after setContentView()?
  • How exactly does Android display what we expect on the screen?
  • Have an overall understanding of Android’s view architecture.
  • Learn to analyze the causes of picture stutter from the root.
  • Learn how to write a smooth App.
  • From the source code to learn Android’s fine thinking.
  • Get two homemade diagrams to help you understand Android’s view architecture.

From the setContentView () to start

public class AnalyzeViewFrameworkActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_analyze_view_framwork); }}Copy the code

The above code is probably more familiar to most Androider users. But you know what happened after that? Where exactly has the layout been added? Oh, my God, there you go!

Most of you probably know that this layout is placed in a parent called DecorView, but I’ll say it again. Take a look at ✌️ below

It might not look like what your friends see in books or on the Internet. Why not? Because I drew it myself, hahaha…

Let’s take a look at the diagram and get a feel for Android’s most basic view framework.

PhoneWindow

As many of you probably know, every Activity has an instance of the Window object. This instance is actually of type PhoneWindow. PhoneWindow, as its name suggests, should be a child of Window!

Each Activity has a PhoneWindow object.

So what does PhoneWindow do? What role does it play in an Activity? I’ll just call PhoneWindow the same as Window.

A Window is literally a Window, similar to the concept of a Window on a PC. But it’s not that accurate. Look at the picture. As you can see, the layout we want to display is put into its mDecor property, which is an instance of DecorView. The next section will be dedicated to the DecorView, so let’s focus on the Window for now. Window also has a more important property, mWindowManager, which is an instance of an implementation class of WindowManager(which is an interface). The thing we normally get with the getWindowManager() method is this MWindows Manager. As the name implies, it is the Window manager, responsible for managing the Window and the content displayed in it. Its actual implementation class is WindowManagerImpl. Maybe you’re looking in PhoneWindow to see where the mWindowManager is instantiated, scrolling up and down without finding it. STOP! MWindowManager is instantiated in its parent. The following code is in window.java.

public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { ... if (wm == null) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); / / get a WindowManager} mWindowManager = ((WindowManagerImpl) wm). CreateLocalWindowManager (this); // We can see from this that wm obtained above is actually WindowManagerImpl type. }Copy the code

We already know that the Window has a DecorView that hosts the layout and a WindowManager that manages it (which is really just an agent, but who it represents later).

DecorView

As mentioned earlier, the layout set by setContentView() in the Activity’s onCreate() is actually placed in the DecorView. We find the DecorView in the figure.

As you can see in the figure, the DecorView inherits FrameLayout and generally adds a default layout first. A DecorCaptionView, for example, places its child layout from top to bottom, equivalent to a LinearLayout. It usually has a title bar and then an mContentRoot to hold the content, and the type of layout depends on the situation. The layout we want to display is in mContentRoot.

The layout set by setContentView() is placed in a DecorView, which is the top layer of the view tree.

WindowManager

As mentioned earlier, WindowManager plays an important role in Windows. Let’s find it in the picture. It is important to note that the mWindowManager in PhoneWindow is actually of type WindowManagerImpl. WindowManagerImpl is an implementation class for the WindowManager interface. This is something I didn’t reflect in the diagram.

WindowManager is created when the Activity executes attach(), and the attach() method is called before onCreate(). About the Activity created I can look at this article: [is probably the most simple history! A figure 3 minutes to let you understand the Activity to start the process, don’t regret! http://www.jianshu.com/p/9ecea420eb52 】. Activity.java

final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window){ ... mWindow = new PhoneWindow(this, window); // create Window... mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! = 0); / / attention! This is creating a Windows Manager. // This method has been described previously. if (mParent ! = null) { mWindow.setContainer(mParent.getWindow()); } mWindowManager = mWindow.getWindowManager(); }Copy the code

Keep looking at the picture. WindowManagerImpl holds a reference to PhoneWindow, so it can manage PhoneWindow. It also holds a very important reference, mGlobal. This mGlobal points to a singleton object of type Windows ManagerGlobal, which has only one for each application. In the figure, I showed that Windows ManagerGlobal maintains all Window decorViews in the application, as well as the Corresponding ViewRootImpl associated with each DecorView. That’s why, as I mentioned earlier, WindowManager is just an agent, and the actual administration is done through Windows ManagerGlobal. Let’s look at a source code example is more clear. To start!

WimdowManagerImpl.java

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { ... mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); // This is actually implemented through Windows ManagerGlobal. }Copy the code

As you can see from the above code, Windows Manager ImpL is really just a proxy for Windows ManagerGlobal. At the same time, this method is very important in the overall Android view frame flow. We know that after the Activity executes onResume(), the interface starts rendering. The reason is that while onResume() is called, the WindowManager addView() method is called to add the view to the window. Combined with my this [is probably the most simple history! A figure 3 minutes to let you understand the Activity to start the process, don’t regret! http://www.jianshu.com/p/9ecea420eb52 】 see, can help you better understand the view of the Android framework. ActivityThread.java

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { ... ViewManager wm = a.getWindowManager(); // Get WindowManager, which is WindowManagerImpl... wm.addView(decor, l); // Add a view... wm.updateViewLayout(decor, l); // When you need to refresh, you will go here... }Copy the code

As you can see above, a view is added or refreshed when the Activity executes onResume(). One thing to explain: WindowManager implements the ViewManager interface.

As you can see in the figure, A WindowManagerGlobal call to addView() adds a DecorView to the array it maintains and creates another key and extremely important ViewRootImpl(which must be covered specifically) type object. It also stores it in an array for maintenance. WindowManagerGlobal.java

public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { ... root = new ViewRootImpl(view.getContext(), display); View.setlayoutparams (wparams); mViews.add(view); mRoots.add(root); // Save to maintain mparams.add (wparams); . root.setView(view, wparams, panelParentView); // Set the necessary properties: view is a DecorView, panelParentView is a PhoneWindow... }Copy the code

You can see that the ViewRootImpl is created when the Activity executes onResume(), and that the DecorView is passed in for management.

WindowManager is created with onCreate(). Its ability to manage Windows is actually implemented through Windows ManagerGlobal. OnResume () is the view that is added to the window via WindowManager.

ViewRootImpl

ViewRootImpl interacts with the system’s WindowManagerService and manages the DecorView rendering and window state. Very important. Find the right place in the picture!

The ViewRootImpl is not a View, but is responsible for managing the View. It works with the system to manage the view tree in a Window. As you can also see from the figure, it holds a reference to the DecorView, and the view tree is the starting point from which the view tree is drawn. As a result, ViewRootImpl is a little more complex and requires a little more depth, and I’ve highlighted its more important components Surface and Choreographer, which will be covered later.

At this point, we’ve gone through the first image together, and now you should have a general understanding of the Android view framework. Let’s take a closer look at Android’s drawing mechanism.

What is the reason why App always freezes up?

Why can the view we set be drawn to the screen? What kind of weirdness is hidden among these? After reading this, you’ll be able to get to the root of why your App is stuck and start thinking about how to fix it.

Again, a diagram shows the process. The Android drawing mechanism is a bit complicated, so your heart may jump at first glance with 10,000 horses 😂. Don’t be afraid! We started at the beginning and combed through this seemingly complex drawing mechanism bit by bit. Why does it look complicated? Because the process only takes a few minutes. Just Do It!

CPU, GPU is to make what ghost?

Hear CPU, GPU all day long, do you know what they are doing? Here is a brief mention to help understand the following content.

In the Drawing architecture of Android, CPU is mainly responsible for measuring, layout, recording and calculating the content into Polygons Polygons or Texture Texture, while GPU is mainly responsible for Rasterization of Polygons or Textture. That’s how you get an image on the screen. After hardware acceleration is used, the GPU shares computing tasks with the CPU, while the CPU focuses on processing logic, thus reducing the burden on the CPU and making the entire system more efficient.

RefreshRate and FrameRate FrameRate

RefreshRate Is the number of screen refreshes per second, which is a fixed value dependent on hardware. On Android, this value is typically 60 Hz, which means the screen refreshes 60 times per second.

The FrameRate FrameRate is the number of frames drawn per second. Generally, as long as the frame count and refresh rate are consistent, you can see smooth graphics. On Android, we should try to maintain a frame rate of 60FPS. But sometimes, due to the complexity of the views, they can be inconsistent.

As shown in the figure, when the frame rate is less than the refresh rate, such as 30FPS < 60HZ in the figure, two adjacent frames will see the same picture, which causes the lag. That’s why we always say that it’s important to make sure a frame is drawn in less than 16ms, just to keep pace with the refresh rate of the screen.

Here’s how Android keeps refresh rates and frame rates in sync.

What is Vsync?

You’ve probably seen Vsync in the game’s Settings, and turning it on often improves game performance. In Android, Vsync is also used to improve display performance. It can force the FrameRate and hardware RefreshRate to be the same.

HWComposer with Vsync have to say things

Look at the picture. Look at the picture. First on the far left we see a class called HWComposer, which is written in c++. It is created when the Android system is initialized, and then starts to work with the hardware to generate the Vsync signal, also known as the HW_Vsync signal in the figure. Of course, it is not always generated, which can cause Vsync signal receivers to receive draw and render commands over and over even when they don’t need them, which can cause serious performance losses because of unnecessary drawing. So it’s designed to wake up and sleep. This allows HWComposer to generate Vsync signals only when needed (for example, when the content on the screen needs to change) and sleep when not needed (for example, when the content on the screen stays the same, each refresh of the screen shows the content in the buffer that has not changed).

As shown, the two receivers of Vsync are SurfaceFlinger(responsible for composing individual surfaces) and Choreographer(responsible for controlling the drawing of views). We’ll talk about that later, but just know what they do for now.

Vsync offset mechanism

To improve efficiency and minimize lag, Vsync was introduced in Android 4.1 and Vsync offset was added in later 4.4.

Figure 1 shows the Vsync mechanism during 4.1. As you can see, when a Vsync signal arrives, the SurfaceFlinger and UI drawing processes start at the same time, causing them to compete for CPU resources, which can take time to allocate and slow down system performance. At the same time, when a Vsync signal is received, frame N is drawn. Frame N is synthesized by SurfaceFlinger when another Vsync signal is received. And need to display on the screen, need to wait for the third Vsync signal. This is relatively inefficient. Hence the Vsync offset mechanism added in Figure 2.4.4.

Figure 2. After Google adds Vsync offset, the original HW_Vsync signal is DispSync and divided into Vsync and SF_Vsync. Where Vsync signals are sent to Choreographer and SF_Vsync to SurfaceFlinger. Theoretically, as long as the offset parameters of phase_app and phase_sf are set properly and the time consumed in the drawing stage is controlled well, the picture will proceed smoothly and orderly like the first few frames in Figure 2. Ideal is always good. In fact, it is difficult to maintain this order and smoothness all the time. For example, Frame_3 is a complex frame that was drawn longer than SurfaceFlinger began to compose, so it must wait for the next Vsync signal to be composed. This results in a lost frame. But even so, as you can see, the efficiency of drawing is greatly improved with the addition of Vsync offset.

As you can see from the figure, the offsets of Vsync and SF_Vsync are controlled by phase_app and phase_sf, respectively, which are adjustable and default to 0 and can be negative. All you need to do is find the boardconfig. mk file to adjust these two values.

Back to ViewRootImpl

Having introduced a few key concepts, let’s now go back to the View wrootimpl and find the corresponding position of the View wrootimpl in the diagram.

As mentioned earlier, view ArotimPL controls the drawing of the entire view tree in a Window. So how does it control it? How exactly does a drawing begin?

When ViewRootImpl is created, one of the key objects mentioned earlier, Choreographer, is acquired. Choreographer exists only one instance per thread and therefore only one Choreographer exists on the UI thread. That is, in general, it is equivalent to a singleton in an application.

Upon initial ViewRootImpl, will realize a Choreographer FrameCallback (this is a Choreographer of the inner class), and post to the Choreographer. As the name suggests, FrameCallback is called back every time it receives a Vsync signal. Choreographer.java

public interface FrameCallback { public void doFrame(long frameTimeNanos); // Once registered with CallbackQueue, Choreographer will call back every time it receives a Vsync signal. }Copy the code

Once FrameCallback is registered, it is called back every time a Vsync signal is received. Using it, we can achieve frame rate monitoring.

ViewRootImpl.java

Private void profileRendering(Boolean Enabled) {// This method is called only when ViewRootImpl is initialized. mRenderProfiler = new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { ... scheduleTraversals(); / / request a Vsync signal, behind also mentions the method mChoreographer. PostFrameCallback (mRenderProfiler); // Re-post FrameCallback into Choreographer each time you call back... }}; . mChoreographer.postFrameCallback(mRenderProfiler); // Post FrameCallback to Choreographer... }Copy the code

An important method, scheduleTraversals(), appears in the code above. Here’s why it’s important. ViewRootImpl.java

void scheduleTraversals() { ... mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); // Post a TraversalRunnable to Choreographer // This is another very important object... }Copy the code

You can see that scheduleTraversals() will post a TraversalRunnable to Choreographer each time it is called, which will cause Choreographer to request a Vsync signal. So this method is used to request a Vsync signal to refresh the interface. In fact, you can see it called in invalidate(), requestLayout(), and so on. The reason is that these operations require a refresh of the interface, so a Vsync signal is requested to start drawing the new interface.

ViewRootImpl.java

final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); // Start traversing the view tree, which means start drawing a frame}}Copy the code

As you can see, every time doTraversal() is called, a series of measurement, layout, and rendering operations begin. During drawing, a Canvas memory block is acquired by the Surface and given to the DecorView for drawing the view. The entire contents of the View are drawn onto this Canvas.

Choreographer is on the move

Callbacks to POST on Choreographer have been mentioned repeatedly, what happened to post in the past? Can see from the picture, all the post operation finally into postCallbackDelayedInternal ().

Choreographer.java

private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { ... synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); // Add Callback to CallbackQueue[] if (dueTime <= now) {scheduleFrameLocked(now); // If the Callback time is up, a Vsync signal is requested // the doFrame() Callback will be called upon receiving it. } else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); msg.arg1 = callbackType; msg.setAsynchronous(true); / / asynchronous messaging, avoid being interceptors to intercept mHandler. SendMessageAtTime (MSG, dueTime); // If it is not time for the callback, send the MSG_DO_SCHEDULE_CALLBACK message to FrameHandelr}}... }Copy the code

The above code adds the Callback posted to Choreographer to Callback[], and when it is called back for this reason, requests a Vsync signal, which is called back when the next Vsync signal is received. If there is no time for the Callback, an MSG_DO_SCHEDULE_CALLBACK message is sent to the FrameHandler, but eventually a Vsync signal is requested and the Callback is called back.

Just a quick word about CallbackQueue: Just a quick word about CallbackQueue. It is similar to MessageQueue in that it is a single linked list structure. In my article “Big Secret! Since Thread, reveal the Android threads of communication devices, and the main Thread of conspiracy http://www.jianshu.com/p/8862bd2b6a29 】 in the article, you can see more about the content of the MessageQueue and Handler mechanism. The difference is that it is also a one-dimensional array, with subscripts representing the type Callback. In fact, with each type of singly linked list structure, it looks more like a two-dimensional array. To simplify the description, suppose you have a MessageQueue[] array containing several MessageQueue. If you look at its creation you will probably see that it was created at Choreographer initialization.

private Choreographer(Looper looper) { mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; // The value of CALLBACK_LAST is 3. for (int i = 0; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new CallbackQueue(); }}Copy the code

Now look at how scheduleFrameLocked(), called in the previous code, requests a Vsync signal.

private void scheduleFrameLocked(long now) { ... / / to figure out whether the current in the UI thread if (isRunningOnLooperThreadLocked ()) {scheduleVsyncLocked (); } else {Message MSG = mhandler. obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true); mHandler.sendMessageAtFrontOfQueue(msg); }} Private void scheduleVsyncLocked() { mDisplayEventReceiver.scheduleVsync(); // Request a Vsync signal via DisplayEventReceiver // This is a hate character, I'll talk about it later. // the MSG_DO_SCHEDULE_VSYNC message also requests the Vsync signal by calling this method. }Copy the code

As mentioned above, Choreographer has only one thread. So, if you were in another thread, you would need to switch to the UI thread through a Handler and then request a Vsync signal.

What is mDisplayEventReceiver?

Private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {/ / this method is used to receive Vsync signal public void onVsync(){ ... Message msg = Message.obtain(mHandler, this); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); // The message type is not set. This is a message of type MSG_DO_FRAME that tells Choreographer to start calling the Callback in CallbackQueue[]} // This method is in the parent class, Public void scheduleVsync() {... nativeScheduleVsync(mReceiverPtr); // Request a Vsync signal}}Copy the code

This gives the class some clarity, and it’s important!

It keeps talking about sending messages to the FrameHandler, keeping it secret. Now let’s look at the FrameHandler himself. Please find the corresponding position in the picture.

private final class FrameHandler extends Handler { public FrameHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_DO_FRAME: // Start the Callback to start drawing the next frame doFrame(system.nanotime (), 0); break; Case MSG_DO_SCHEDULE_VSYNC: // Request a Vsync signal doScheduleVsync(); break; Case MSG_DO_SCHEDULE_CALLBACK: // A Vsync signal doScheduleCallback(MSG. Arg1); break; }}}Copy the code

The FrameHandler handles three types of messages primarily on the UI thread.

  • MSG_DO_FRAME: the value is 0. A message of this type is sent when a Vsync signal is received, and the Callback in CallbackQueue[] begins. For example, as mentioned above, there are two important callbacks in ViewRootImpl, FrameCallback (request Vsync and register Callback again) and TraversalRunnable (perform doTraversal() to start drawing the interface) that are frequently registered.
  • MSG_DO_SCHEDULE_VSYNC: The value is 1. This message is sent when a Vsync message needs to be requested (that is, when something on the screen needs to be updated). After receiving Vsync, repeat the previous step.
  • MSG_DO_SCHEDULE_CALLBACK: the value is 2. Request a Callback. A Vsync signal is actually requested, followed by an MSG_DO_FRAME message, followed by a callback.

FrameHandler is not complicated, but plays an important role in the UI drawing process, so be sure to tease out the process with diagrams.

SurfaceFlinger and Surface in a nutshell

As we may have seen in the introduction of Vsync, the Android system now virtualizes HW_VSYNC as two Vsync signals. One is VSYNC, which is sent to Choreographer, which has been talking about above, to trigger the rendering of view trees. The other is SF_VSYNC, which is sent to the SurfaceFlinger that I’ll talk about next, and is used to trigger the composition of the Surface, that is, the composition of various Window frames. Let’s take a quick look at the SurfaceFlinger and Surface. Since this part is basically written in c++, I will focus on the principle.

Hidden behind the Surface

As you know, our view needs to be drawn. So where are they drawn? Perhaps many children immediately think of a word: Canvas. But, yeah! It’s drawn on the Canvas. So where does Canvas come from? Yes, it can come out New. But as mentioned earlier, the view tree in our Window is drawn to a Canvas provided by Surface. Forget the children’s shoes face wall thought 😄.

The Canvas actually represents a chunk of memory used to store drawn data. In the Canvas constructor you can see:

public Canvas() { ... mNativeCanvasWrapper = initRaster(null); // Retrieves a block of memory and returns a long tag or index for that memory. . }Copy the code

As you can see, the Canvas is actually basically holding an index long mNativeCanvasWrapper for a memory block to draw. Each time the index is used to find the corresponding block of memory, and the data is drawn into memory. Such as:

public void drawRect(@NonNull RectF rect, @NonNull Paint paint) { native_drawRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance()); // Draw a rectangle in the memory of the mNativeCanvasWrapper tag. }Copy the code

Just to be brief. Android draws graphics through the graphics library Skia(mainly 2D) or OpenGL(mainly 3D). What is a graphics library? Just like when you use an artboard to draw on a PC, the artboard is the equivalent of the Android graphics library, which provides a set of standardized tools for drawing. For example, when we drawRect(), we actually write a rectangle of data to memory.

Anyway, let’s go back to the Surface. When ViewRootImpl is executed to the draw() method (that is, drawing the graph data), the decision is made to use CPU soft drawing or GPU hard drawing depending on whether hardware acceleration is enabled (which is the default starting from Android 4.0). If soft drawing is used, the graph data will be drawn on the default CompatibleCanvas of Surface (the only difference with normal Canvas is that Matrix is processed to improve compatibility on different devices). If hard drawing is used, the graph data is drawn on the DisplayListCanvas. DisplayListCanvas is drawn by the GPU using the openGL graphics library, so it is more efficient.

As mentioned above, every Window has its own Surface, which means that there are multiple surfaces in an application. The purpose of Surface is to manage the Canvas used to draw the view tree. The Surface is shared with the SurfaceFlinger, and since it implements the Parcelable interface it is expected to be serialized. In fact, the drawing data in the Surface is shared with SurfaceFlinger through anonymous shared memory, so that SurfaceFlinger can find the drawing data in the memory region corresponding to different Surface and then synthesize it.

Compositor SurfaceFlinger

SurfaceFlinger is a service on the system. As mentioned earlier, it is responsible for synthesizing the contents of each Surface into a cache for display on the screen. SurfaceFlinger synthesized the Surface layer by layer according to the Z-order of the Surface. For example, a Dialog Surface will be on top of the Activity Surface. And then I’m not going to talk about this anymore.

Can you finally tell me why your App is stuck

Through the understanding of Android drawing mechanism, we know that the root cause of application lag is that the drawing and rendering synthesis process cannot be completed within 16ms, because the hardware refresh rate of Android platform is 60HZ, which is about 16ms refresh. Failure to do this within 16ms will cause the screen to repeat the previous frame, causing a stutter. In this 16ms, all measurements, layouts, rendering and compositing of the view tree need to be completed. And our optimization work is mainly aimed at this process.

Complex view tree

If the view tree is complex, the entire Traversal process becomes longer. Therefore, we need to control the complexity of the view tree during development. Reduce unnecessary level nesting. Using RelativeLayout, for example, reduces the nesting of complex layouts. For example, using shock! This control is definitely worth bookmarking. Easily implement rounded corners, such as text stroke, status indication effect http://www.jianshu.com/p/cfe18cbc6924 】 😄, this control can reduce the need to display text, and the layout of the images and the demand of the special background of complexity, all the things by a control implementation.

Frequent requestlayout ()

If requestLayout() is triggered frequently, this will result in frequent layout calculations within a frame, which will cause the entire Traversal process to take longer. Some ViewGroup controls, such as RelativeLayout, compute the position of the child View with two Layout () operations within a frame. This small number of operations does not cause noticeable performance problems. However, frequent layout() calculations within a frame can cause serious performance problems, and each calculation is time consuming! RequestLayout () adds views that need to be relaid to a List called mLayoutRequesters in the ViewRootImpl, and these views will all be relaid () in the next frame. Usually after a control is loaded, if nothing changes, it will not relayout () every time it is refreshed, because this is a time-consuming calculation. So if you have a lot of views to perform layout() on every frame, you can expect your interface to get jammed! Card to explode! Note that setLayoutParams() also ends up calling requestLayout(), so don’t spoil it! Be careful about requestLayout() when writing code.

The UI thread is blocked

If the UI thread is blocked, then obviously our Traversal process is blocked too! There’s no problem with the picture stalling. That’s why people keep saying don’t do time-consuming operations on the UI thread. In general, UI threads block for the following reasons.

  • Read and write IO data in the UI thread. It’s a very time-consuming process, okay? Don’t do that. If you don’t want to get a jammed App, put all the IO operations into child threads.
  • Perform complex operations in the UI thread. The operation itself is a time-consuming operation, but of course the simple operation is almost instantaneous, so you don’t feel that it is time-consuming. But for very complex operations, the consumption of time is very eye-watering! If you don’t want to get a jammed App, put complex operations into child threads.
  • Perform complex data processing in the UI thread. I’m talking about data encryption, decryption, encoding and so on. These operations require complex calculations, especially if the data is complex. If you don’t want to get a jammed App, put complex data processing into child threads.
  • Frequent GC occurs, resulting in frequent interruption of the UI thread. In Java, GC means stop-the-world, which means all other threads are suspended. How terrible! It is acceptable for normal GC to cause occasional screen stutter, but it is very painful to have frequent stutter. Frequent GC the culprit is the memory of jitter, this time you need to look at my this article Android memory, memory jitter http://www.jianshu.com/p/69e6f894c698 】 【. Simply put, a large number of objects are created frequently in a short period of time, causing the threshold for GC to be reached, and then GC occurs. If you don’t want to get a jammed App, do a good job of memory management, even if it’s Java.
  • Deliberately blocking the UI thread. Well, I’m sure no one would do that. Like sleep(), right?

conclusion

  • Take out spare time to write articles to share the need for power, but also please you see the officer move a small hand point praise, encourage the next 😄
  • I’ve been creating new dry goods from time to time. To get on, just go to my profile page and follow me. Start then ~

The whole article down, I believe that children’s shoes on The Android drawing mechanism also have a more comprehensive understanding. Do you now feel confident that you know what you’re doing when you go back to writing code? 😄

Refer to the link

  1. Implementing VSYNC:https://source.android.com/devices/graphics/implement-vsync
  2. SurfaceFlinger and Hardware Composer:https://source.android.com/devices/graphics/arch-sf-hwc
  3. Surface and SurfaceHolder:https://source.android.com/devices/graphics/arch-sh
  4. Implementing the Hardware Composer HAL:https://source.android.com/devices/graphics/implement-hwc
  5. Probably the easiest ever! A picture of 3 minutes to let you understand the Activity start process, no regret! http://www.jianshu.com/p/9ecea420eb52
  6. Big secret! Since the Thread, reveal the Android threads of communication devices, and the main Thread of http://www.jianshu.com/p/8862bd2b6a29
  7. Shock!!! This control is definitely worth bookmarking. Easily implement the rounded, text stroke and status indication effect of http://www.jianshu.com/p/cfe18cbc6924
  8. Android memory base – memory thrashing at http://www.jianshu.com/p/69e6f894c698
  9. Android Performance Optimization render http://hukai.me/android-performance-render/
  10. Android hardware to accelerate the introduction of principle and implementation of http://tech.meituan.com/hardware-accelerate.html
  11. Android SurfaceFlinger http://blog.csdn.net/yangwen123/article/details/17001405 the VSync signal processing analysis
  12. Android Vsync principle of http://www.10tiao.com/html/431/201601/401709603/1.html
  13. Android Choreographer Source code analysis http://www.jianshu.com/p/996bca12eb1d?utm_campaign=hugo&utm_medium=reader_share&utm_content=note
  14. Android application window (Activity) View object (View) the process of creating an analysis: http://blog.csdn.net/luoshengyang/article/details/8245546
  15. Android 4.4 (KitKat) virtualization VSync signal in http://blog.csdn.net/jinzhuojun/article/details/17293325
  16. Understanding Necessity of Android VSYNC signals: http://stackoverflow.com/questions/27947848/understanding-necessity-of-android-vsync-signals

See here children’s shoes quickly reward yourself with a spicy stick!