The principle of Androidt graphics drawing is learned from the bottom layer to the upper layer (3) The life cycle of the activity when the drawing is completed and the first frame is displayed on the screen

Reprinted from: Android application startup optimization: an implementation and principle of DelayLoad

http://androidperformance.com/2015/11/18/Android-app-lunch-optimize-delay-load.html


    The author of the article was originally analyzing - "Android Application Startup Optimization: An Implementation and Principle of DelayLoad " to perform data Load immediately after the first frame of the application is displayed, without considering the length of the Delay time. This method is very bad, so it needs to be done the first time the graph appears.

    However, the analysis of the time point when the first frame of Android graphics is rendered to the screen is very in place. The previous two articles have made it clear how the bottom layer of Android graphics is drawn, but where is the first frame of the picture? What time did it appear? Therefore, an article is needed to sort out the time point of the activity when the first frame is drawn to the screen.


In Android development, application startup speed is a very important point, and application startup optimization is also a very important process. For application startup optimization, in fact, the core idea is to do less during the startup process. The specific practice is nothing more than the following: kind:

  1. Asynchronous loading
  2. lazy loading
  3. lazy loading

There is no need to explain them one by one. The estimation of startup optimization has been used. This article will explain in detail the implementation of a delayed loading and its principle.
In fact, the implementation of this loading is very simple, but the principle may be It is more complicated, and also involves Looper/Handler/MessageQueue/VSYNC, etc. As well as some of the problems encountered, there will be some additional thinking of my own.

1. Implementation of optimized DelayLoad

When it comes to DelayLoad, the first thing you may think of is to call the Handler.postDelayed method in onCreate, and put the things that need to be loaded by Delay to be initialized here. This is also a more convenient method. Delay for a period of time and then execute, At this time, the application has been loaded and the interface has been displayed, but this method has a fatal problem: how long is the delay?
Everyone knows that on high-end Android models, the application startup is very fast, and only Delay is required at this time. A very short time is enough, but on low-end models, the startup of the application is not so fast, and now the application is compatible with the old model, it often takes a long time to delay, which brings about the difference in experience is obvious.

Here is the optimization plan:

  1. First, create Handler and Runnable objects, in which the run method of the Runnable object updates the UI thread.

     
           
    1
    2
    3
    4
    5
    6
    7
    8
     
           
    private Handler myHandler = new Handler();
    private Runnable mLoadingRunnable = new Runnable() {
    @Override
    public void run () {
    updateText(); //Update UI thread
    }
    };
  2. Add the following code to the onCreate of the main Activity

     
           
    1
    2
    3
    4
    5
    6
    7
     
           
    getWindow().getDecorView().post(new Runnable() {
    @Override
    public void run () {
    myHandler.post(mLoadingRunnable);
    }
    });

其实实现的话非常简单,我们来对比一下三种方案的效果.

2. 三种写法的差异对比

为了验证我们优化的 DelayLoad的效果,我们写了一个简单的app , 这个 App 中包含三张不同大小的图片,每张图片下面都会有一个 TextView , 来标记图片的显示高度和宽度. MainActivity的代码如下:

 
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
 
     
public class MainActivity extends AppCompatActivity {
private static final int DEALY_TIME = 300 ;
private ImageView imageView1;
private ImageView imageView2;
private ImageView imageView3;
private TextView textView1;
private TextView textView2;
private TextView textView3;
private Handler myHandler = new Handler();
private Runnable mLoadingRunnable = new Runnable() {
@Override
public void run() {
updateText();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView1 = (ImageView) findViewById(R.id.image1);
imageView2 = (ImageView) findViewById(R.id.image2);
imageView3 = (ImageView) findViewById(R.id.image3);
textView1 = (TextView) findViewById(R.id.text1);
textView2 = (TextView) findViewById(R.id.text2);
textView3 = (TextView) findViewById(R.id.text3);
// 第一种写法:直接Post
myHandler.post(mLoadingRunnable);
// 第二种写法:直接PostDelay 300ms.
// myHandler.postDelayed(mLoadingRunnable, DEALY_TIME);
// 第三种写法:优化的DelayLoad
// getWindow().getDecorView().post(new Runnable() {
// @Override
// public void run() {
// myHandler.post(mLoadingRunnable);
// }
// });
// Dump当前的MessageQueue信息.
getMainLooper().dump(new Printer() {
@Override
public void println(String x) {
Log.i("Gracker",x);
}
},"onCreate");
}
private void updateText() {
TraceCompat.beginSection("updateText");
textView1.setText("image1 : w=" + imageView1.getWidth() +
" h =" + imageView1.getHeight());
textView2.setText("image2 : w=" + imageView2.getWidth() +
" h =" + imageView2.getHeight());
textView3.setText("image3 : w=" + imageView3.getWidth() +
" h =" + imageView3.getHeight());
TraceCompat.endSection();
}

我们需要关注两个点:

  • updateText 这个函数是什么时候被执行的?
  • App 启动后,三个图片的长宽是否可以被正确地显示出来?
  • 是否有 Delay Load 的效果?

2.1 第一种写法

  1. updateText执行的时机?
    下面是第一种写法的Trace图:
    first spelling第一种写法
    可以看到 updateText 是在 Activity 的 onCreate/onStart/onResume三个回调执行完成后才去执行的.

  2. 图片的宽高是否正确显示?
    first spelling第一种写法

    从图片看一看到,宽高并没有显示. 这是为什么呢? 这个问题就要从Activity 的 onCreate/onStart/onResume三个回调说起了. 其实Activity 的 onCreate/onStart/onResume三个回调中,并没有执行Measure和Layout操作, 这个是在后面的performTraversals中才执行的. 所以在这之前宽高都是0.

  3. 是否有 Delay Load 的效果?
    并没有. 因为我们知道, 应用启动的时候,要等两次 performTraversals 都执行完成之后才会显示第一帧, 而 updateText 这个方法在第一个 performTraversals 执行之前就执行了. 所以 updateText 方法的执行时间是算在应用启动的时间里面的.

2.2 第二种写法

第二种写法我们Delay了300ms .我们来看一下表现.

  1. updateText执行的时机?
    The second way of writing第二种写法

    可以看到,这种写法的话,updateText是在两个performTraversals 执行完成之后(这时候 APP 的第一帧才显示出来)才去执行的, 执行完成之后又调用了一次 performTraversals 将 TextView 的内容进行更新.

  2. 图片的宽高是否正确显示?
    The second way of writing第二种写法

    从上图可以看到,图片的宽高是正确显示了出来. 原因上面已经说了,measure/layout执行完成后,宽高的数据就可以获取了.

  3. 是否有 Delay Load 的效果?
    不一定,取决于 Delay的时长.
    从前面的 Trace 图上我们可以看到 , updateText 方法由于 Delay 了300ms, 所以在应用第一帧显示出来170ms之后, 图片的文字信息才进行了更新. 这个是有 Delay Load 的效果的.
    但是这里只是一个简单的TextView的更新, 如果是较大模块的加载 , 用户视觉上会有很明显的 “ 空白->内容填充” 这个过程, 或者会附加”闪一下”特效…这显然是我们不想看到的.

    有人会说:可以把Delay的时间减小一点嘛,这样就不会闪了. 话是这么说,但是由于 Android 机器的多元性(其实就是有很多高端机器,也有很多低端机器) , 在这个机子上300ms的延迟算是快,在另外一个机子上300ms算是很慢.

    We adjust the Delay time to 50ms, and its Trace graph is as follows:

    The second way of writing: Delay 50msThe second way of writing: Delay 50ms

    As you can see, the updateText method is executed after the first performTraversals, so there is no Delay Load effect (although the width and height are displayed correctly, because the layout and measure are executed in the first performTraversals method).

2.3 The third way of writing

After the first two methods, we will think, if the Delay method can not be used, the updateText method can be executed immediately after the second performTraversals method is executed (that is, the first frame of the APP is displayed on the screen), then the start When the function of Delay Load is reached, the width and height of the picture can be displayed correctly.
The third way of writing is this effect:

  1. When does updateText execute?

    The third way of writingThe third way of writing

    You can see this way of writing. updateText is executed immediately after the second performTraversals method is executed, and then after the next VSYNC signal comes, the TextView is updated.

  2. Is the width and height of the picture displayed correctly?
    Of course it is displayed correctly. As shown in the figure:
    The third way of writingThe third way of writing

  3. Does it have the effect of Delay Load?
    From the Trace chart, it has the effect of Delay Load, and the data can be loaded immediately after the first frame is displayed, regardless of the length of the delay time.


of

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324379566&siteId=291194637