关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 安卓开发 »Android应用启动优化:一种DelayLoad的实现和原理

    Android应用启动优化:一种DelayLoad的实现和原理

    2015-11-22 00:00:00 出处:希尔瓦娜斯女神
    分享

    0. 应用启动优化概述

    在 Android 开发中,应用启动速度是一个非常重要的点,应用启动优化也是一个非常重要的过程.对于应用启动优化,其实核心思想就是在启动过程中少做事情,具体实践的时候无非就是下面几种:

    异步加载 延时加载 懒加载

    不用一一去解释,做过启动优化的估计都使用过,该文文章将详细讲解一下一种延时加载的实现以及其原理.其实这种加载的实现是非常简单的,但是其中的原理可能比较复杂,还涉及到Looper/Handler/MessageQueue/VSYNC等.以及其中碰到的一些问题,还会有一些我自己额外的思考.

    1. 优化后的DelayLoad的实现

    一提到DelayLoad,大家可能第一时间想到的就是在 onCreate 里面调用 Handler.postDelayed方法, 将需要 Delay 加载的东西放到这里面去初始化, 这个也是一个比较方便的方法. Delay一段时间再去执行,这时候应用已经加载完成,界面已经显示出来了, 不过这个方法有一个致命的问题: 延迟多久 大家都知道,在 Android 的高端机型上,应用的启动是非常快的 , 这时候只需要 Delay 很短的时间就可以了, 但是在低端机型上,应用的启动就没有那么快了,而且现在应用为了兼容旧的机型,往往需要 Delay 较长的时间,这样带来体验上的差异是很明显的.

    这里先说优化方案:

    首先 , 创建 Handler 和 Runnable 对象, 其中 Runnable 对象的 run方法里面去更新 UI 线程.
    private Handler myHandler = new Handler();
    private Runnable mLoadingRunnable = new Runnable() {
    @Override
    public void run() {
    updateText(); //更新UI线程
    }
    };
    在主 Activity 的 onCreate 中加入下面的代码
    getWindow().getDecorView().post(new Runnable() {
    @Override
    public void run() {
    myHandler.post(mLoadingRunnable);
    }
    });

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

    2. 三种写法的差异对比

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

    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 第一种写法

    updateText执行的时机

    下面是第一种写法的Trace图:

    Android应用启动优化:一种DelayLoad的实现和原理

    可以看到 updateText 是在 Activity 的 onCreate/onStart/onResume三个回调执行完成后才去执行的.

    图片的宽高是否正确显示

    Android应用启动优化:一种DelayLoad的实现和原理

    从图片看一看到,宽高并没有显示. 这是为什么呢 这个问题就要从Activity 的 onCreate/onStart/onResume三个回调说起了. 其实Activity 的 onCreate/onStart/onResume三个回调中,并没有执行Measure和Layout操作, 这个是在后面的performTraversals中才执行的. 所以在这之前宽高都是0. 是否有 Delay Load 的效果 并没有. 因为我们知道, 应用启动的时候,要等两次 performTraversals 都执行完成之后才会显示第一帧, 而 updateText 这个方法在第一个 performTraversals 执行之前就执行了. 所以 updateText 方法的执行时间是算在应用启动的时间里面的.

    2.2 第二种写法

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

    updateText执行的时机

    Android应用启动优化:一种DelayLoad的实现和原理

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

    图片的宽高是否正确显示

    Android应用启动优化:一种DelayLoad的实现和原理

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

    是否有 Delay Load 的效果

    不一定,取决于 Delay的时长.

    从前面的 Trace 图上我们可以看到 , updateText 方法由于 Delay 了300ms, 所以在应用第一帧显示出来170ms之后, 图片的文字信息才进行了更新. 这个是有 Delay Load 的效果的.

    但是这里只是一个简单的TextView的更新, 假如是较大模块的加载 , 用户视觉上会有很明显的 “ 空白->内容填充” 这个过程, 或者会附加”闪一下”特效…这显然是我们不想看到的.

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

    我们将Delay时间调整为50ms, 其Trace图如下:

    Android应用启动优化:一种DelayLoad的实现和原理

    可以看到,updateText 方法在第一个 performTraversals 之后就执行了,所以也没有 Delay Load 的效果(虽然宽高是正确显示了,因为在第一个 performTraversals 方法中就执行了layout和measure).

    2.3 第三种写法

    经过前两个方法 , 我们就会想, 假如能不使用Delay方法, updateText 方法能在 第二个performTraversals 方法执行完成后(即APP第一帧在屏幕上显示),马上就去执行,那么即起到了 Delay Load的作用,又可以正确显示图片的宽高.第三种写法就是这个效果:

    updateText执行的时机

    Android应用启动优化:一种DelayLoad的实现和原理

    可以看到这种写法. updateText 在第二个 performTraversals 方法执行完成后马上就执行了, 然后下一个 VSYNC 信号来了之后, TextView就更新了.

    图片的宽高是否正确显示

    当然是正确显示的.如图:

    Android应用启动优化:一种DelayLoad的实现和原理

    是否有 Delay Load 的效果
    从 Trace 图上看, 是有 Delay Load的效果的, 而且可以在应用第一帧显示后马上进行数据 Load , 不用考虑 Delay时间的长短.

    3. 一些思考

    关于优化的 Delay Load 的实现,从代码层面来看其实是非常简单的.其带来的效果也是很赞的.但是实现之后我们还需要思考一下,为何这么做就可以实现这种功能呢 很显然要回答这个问题,我们需要知道更底层的一些东西.这个还涉及到 Handler/Message/MessageQueue/Looper/VSYNC/ViewRootImpl等知识. 往大里说应该还涉及到AMS/WMS等.由于涉及到的东西比较多,我就不在这一篇里面阐述了, 下一篇文章将会从从原理上讲解一下为何优化的 Delay Load 会起作用.

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    SQL汉字转换为拼音的函数

    windows 7系统无法运行Photoshop CS3的解决方法

    巧用MySQL加密函数对Web网站敏感数据进行保护

    MySQL基础知识简介

    Windows7和WinXP下如何实现不输密码自动登录系统的设置方法介绍

    windows 7系统ip地址冲突怎么办?windows 7系统IP地址冲突问题的

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。