IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android:启动优化 -> 正文阅读

[移动开发]Android:启动优化

一、前言

首先,我们先提出一个问题,为什么要做启动优化?

随着项目的迭代,App的功能越来越丰富,无可避免的是我们将会引入更多的第三方库及各种SDK,因此App在启动时要做的初始化工作也会更繁重,不当的初始化行为就会拖慢App的启动响应速度,给用户带来糟糕的使用体验。

既然是启动优化,我们就需要先了解应用的启动类型:

  • 冷启动 :应用从头开始启动,系统进程在冷启动后才创建应用进程,发生冷启动的情况包括应用自设备启动后或系统终止应用后首次启动。
  • 热启动 :将处于后台中的应用进程恢复显示到前台,如果应用中的所有Activity都还驻留在内存中,则应用可无须重复对象初始化、布局扩充和呈现。
  • 温启动 : 应用进程还在,但activity已经从栈中推出销毁,再次启动应用需要重新创建对象。

冷启动流程图:

冷启动的链路包含热启动和温启动,因此启动优化主要是对冷启动而言。

熟悉Android系统启动流程的小伙伴知道直到我们点击Launcher上的应用启动图标,才真正的进入到App的启动流程,即从此节点之后才是我们的可控范围,由此可以引出第一个启动优化点黑白屏优化?,此优化方案虽然不能缩短App的启动时间,但从App交互设计上给予了用户及时的操作反馈,提升了一些用户体验。由于之前介绍过相关知识点,大家可点击链接查看,本篇中不再赘述,接下来正式开始介绍启动优化。

二、启动优化

2.1 启动时间测量

测量启动时间的目的有两个:

  1. 找到需要优化的点,即哪里耗时严重
  2. 启动优化效果验证,是否达到预期时间

时间测量方式:

  • 系统日志输出

在Android 4.4及以上版本,App启动时会在logcat输出一行日志,会打印出名为Displayed的值,此值代表从进程启动到在屏幕上完成对应Activity的绘制所经过的时间。

?

  • adb命令
#com.example.test : 包名
#MainActivity :App的启动Activity
adb shell am start -W com.example.test/.MainActivity

?

点home键推到后台,再运行adb命令:

?

点back键推到后台,再运行adb命令:

在此我们也验证了不同启动方式的差异:冷>温>热?

  • 手动(代码)获取

手动添加log日志,打印时间戳。优点:可在线上使用。 缺点:只能记录应用内耗时。

2.2 方法耗时统计

  • traceview统计

可以用代码统计或AndroidStudio自带的cpu profiler。

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //文件名,文件路径:扩展存储路径(sdcard)
        Debug.startMethodTracing("spend_time");
        //
        //各种初始化代码
        //
        Debug.stopMethodTracing();
    }

?

橙色:系统代码调用

绿色:自己代码调用

蓝色:第三方代码调用?

用as自带cpu profiler的话,需提前开启设置

可以查看耗时数据,工具具体使用方法大家可自行学习。??需要注意的是此工具对代码的侵入性较高,会拖慢代码的运行速度,所以真实耗时会稍小一点,不过不影响我们分析问题。?

  • systrace统计

需要python脚本来记录,Android9.0及以上版本的设备可以开启跟踪记录。官方文档

?添加跟踪代码,并运行到设备。

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //Debug.startMethodTracing("spend_time");
        //
        //各种初始化代码
        //
        //Debug.stopMethodTracing();
        Trace.beginSection("spend_time1");
        //
        //各种初始化代码
        //
        Trace.endSection();
    }
}

然后进入到systrace.py文件所在路径,(替换成自己的sdk路径)

/Users/zhoumohan/Library/Android/sdk/platform-tools/systrace

运行命令:

python systrace.py -a 应用包名 -o mynewtrace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res

?可能会报错:

ImportError: No module named six

?解决方案

?随后重新运行,会生成跟踪记录:mynewtrace.html,可在浏览器查看

  • aop方式统计

通过自定义注解及AspectJ框架,对需要检测的方法的前后进行代码注入,从而统计执行耗时,大家可参考AOP思想实现集中式登录,用户行为统计框架,或自行学习相关知识点,这里就不做展开。

2.3 优化方式

  • 按需初始化

此处针对于多进程App,我们知道进程是相互隔离的,所以有多少个进程,项目中的Application就会被执行多少次,因此我们可以根据不同的进程进行对应的初始话操作。

public class App extends Application {
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public void onCreate() {
        super.onCreate();
        String processName = getProcessName();
        if (processName != null) {
            if (processName.equals("进程名称")) {
                //...需要在不同进程下运行的代码
            }
        }
    }
}

?示例中获取进程名适用于9.0及以上,适配低版本可参考android 获取当前进程的名称

  • 异步初始化

主要是通过使用多个子线程来初始化,达到并行执行,缩短运行时间的目的。

public class App extends Application {
    ExecutorService executorService;
    int coreSize;
    @Override
    public void onCreate() {
        super.onCreate();
        coreSize = Runtime.getRuntime().availableProcessors();
        executorService = Executors.newFixedThreadPool(Math.max(2,Math.min(coreSize-1,4)));

        asyncInit(new Runnable() {
            @Override
            public void run() {
                //SDK1.init()
            }
        });

        asyncInit(new Runnable() {
            @Override
            public void run() {
                //SDK2.init()
            }
        });
        //等等初始化操作...
    }

    private void asyncInit(Runnable runnable){
        executorService.submit(runnable);
    }

}

?需要注意一下的是,放到各个子线程进行初始化的代码有没有先后顺序和调用关系,相关的初始话最好放到一个线程中,来保证代码的逻辑正确性,做异步优化时应考虑清楚一下几点:

  1. 能不能做异步优化
  2. 执行的方法是否有先后顺序
  3. 异步后代码是否能正确执行
  • 延迟初始化

即仅初始化立即需要用到的对象,不要创建全局静态对象,而是移动到单例模式,在程序第一次使用它的时候进行初始化。

  • 空闲时初始化

监听应用空闲时间,在空闲时间进行初始化。这里用到了IdelHandle的特性。

public class DelayInit {
    private Queue<Runnable> delayQueue = new LinkedList<>();
    public void add(Runnable runnable){
        delayQueue.add(runnable);
    }

    public void start(){
        Looper.myQueue().addIdleHandler(() -> {
            Runnable poll = delayQueue.poll();
            if (poll != null){
                poll.run();
            }
            return !delayQueue.isEmpty();
        });
    }
}

同时也需要注意初始化对象和使用对象的时序性。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-25 11:39:46  更:2022-05-25 11:40:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 0:50:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码