我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android性能优化(一)启动优化

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android性能优化(一)启动优化

        以前做手机的时候,我非常重视app的性能优化。其实一直以来,在工作中我总会去强调性能优化的重要性。但是,很多时候,由于一些外界因素,我们对app的一些性能指标不会那么重视。但是,性能优化依然是做好一个产品的重中之重。试想一下,如果用户费了很多时间和流量下载了我们的app,当人家安装好启动app时,却发现我们的app点了之后,很长时间没反应。那如果我是用户,我会二话不说卸载掉。因此,app的性能优化还是很重要且很有必要的,我接下来会总结一下Android性能优化的一些相关技术和知识,这篇博客主要总结一下启动优化。

一、前言

        在我总结启动优化之前,我先说些题外话。可能有很多朋友,工作很多年了,也没接触过或者没有实际做过性能优化。我说这个,并不是想展示自己多牛逼,相反,恰恰是因为自己初入职场时太菜。我自己接触性能优化算是职业生涯中比较早的时候吧,而这竟完全是因为自己第一份工作时,写出了非常烂的代码。校招入职后一个多月,公司6个月的培养计划我早就提前执行完了,信心满满的我,主动找主管要了一个开发工作,是基于某公司的算法库实现某种照片美化的功能。当然,那时候还没有正式排期,只是我先拿到算法库开始集成。JNI,NDK,查一些资料,最后搭建好了NDK开发环境。用了没几天时间,开发好了。拿去给我主管看,我主管看后说,你这速度太慢了,掐着秒表给我计算,足足7S!!!我当时不解了,做功能不就是把功能做出来就好了吗,什么是性能,不知道啊。我主管就让我去尝试优化一下,看看能不能优化到1S以内。我当时一听,7S到1S,虽然我数学不好,但是听到这个,我心里还是咯噔了一下,这怎么可能,这已经是动用了我所有的能力了。好,也就是从那时候开始,正式接触性能优化,这也伴随了我很长一段时间的职业生涯。

二、app启动

        首先,我们引用一下谷歌给出的app启动的三种方式:冷启动,热启动,温启动。啥?app还有这么多启动方式,冷,热,温,难道是跟启动app时的环境温度有关?当然了,这么说我觉得也是说的过去的。只不过,这个环境,不是我们理解的室内外环境,而是系统环境。

1、冷启动

        什么是冷启动,就是在系统中不存在当前app进程的情况下,点击app图标启动app。比如初次安装完app启动app或者清除app数据后启动app,这样app的启动需要经过两个步骤:(1)application的创建(2)activity生命周期。在当前系统中不存在任何该app的进程实例,不存在任何的activity实例,所以说,当前的系统环境是“冷”的,这样的app启动速度也是最慢的。

2、温启动

        温启动,其启动速度是介于冷启动和热启动之间的。温启动,就是说在application存在的情况下去启动app,这样只会走activity的生命周期,也就是冷启动的第二阶段。例如:某些手机系统的app,点击系统返回键退出app,再重新启动app。这种时候,app的进程还是存在的,只执行activity的生命周期。所以说,当前的系统环境是“温”的,因为进程还在。

3、热启动

        毫无疑问,这是启动最快的了。热启动,就是在application和activity都存在的情况下启动app,这样只会走activity生命周期的一部分。例如,最常见的就是点击系统home键或者recent键后再次进入app,其实就是前后台的切换。所以说呢,当前的系统环境是热的,因为我的进程和activity都在。

三、优化方向

        在说优化防线之前,再详细说一下冷启动的过程。其实,我们上面说要经过两个步骤,有点不太准确。在创建application之前,系统还会做一些准备工作。

        (1)创建application前,系统会做一些准备工作,具体如下:启动app——>创建空白Window——>创建进程。

        (2)创建了application后,接下来的一系列流程如下:创建进程——>启动主线程——>启动Activity

        (3)启动Activity后,我们就知道基本的流程了,那就是执行Activity生命周期,在各个生命周期中加载布局,展示布局。

        通过上面对冷启动流程的总结,毫无疑问,我们优化的方向,就是针对application和Activity来进行,更详细点,就是针对application和activity的生命周期来进行。

四、启动时间的测量 1、adb命令

        使用如下adb命令可以获取app启动的时间:adb shell am start -W [package]/[.MainActivity]。例如:

adb shell am start -W com.example.tuduoptimize/.MainActivity

        使用上述命令,启动我的tuduoptimize项目,打印出的信息如下:

       

(1)ThisTime:是打开最后一个Activity的时间。

(2)TotalTime:是打开所有Activity的时间。

(3)WaitTime:AMS启动activity的总耗时。

2、打印activity启动时间

        这种方式,其实就是在我们认为开始启动的时间点打印当前系统时间,在我们认为启动完成后的地方打印当前系统时间,取二者的和,得到启动耗时。

        对于上面打印系统时间的方法,写一个工具类,方便我们打印:


package com.example.tuduoptimize;
import android.util.Log;
public class LunchTimeUtil {
    private static final String TAG = "LunchTimeUtil";
    private static long startTime;
    public static void startRecord() {
        startTime = System.currentTimeMillis();
    }
    public static void endRecord(String msg) {
        long costTime = System.currentTimeMillis() - startTime;
        Log.d(TAG, "CostTime:" + costTime + "msg:" + msg);
    }
}

(1)开始启动

        开始启动的时间,我们一般放在Application的attachBaseContext方法中。


@Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        LunchTimeUtil.startRecord();
    }

(2)结束启动

        这个结束启动的时间,我们需要根据我们具体的项目来确定。例如我的空项目,只是加载了一个布局,那么我放在onWindowsFocusChanged()中。

@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        LunchTimeUtil.endRecord("onWindowFocusChanged");
    }
五、性能优化工具TraceView

        进行性能优化,需要借助一些工具,帮助我们分析app启动耗时以及耗时的地方。相信大家都或多或少的用过或者听说过一些性能优化工具。在这里呢,我介绍一下TraceView的使用。

        在使用TraceView分析trace文件之前,我们首先得得到一个trace文件。那么如何生成trace文件呢?其实很简单,我们在我们需要生成trace文件的方法中,简单的两行代码即可生成trace文件。例如我在Application的onCreate中,分析initSdk这个方法:


@Override
    public void onCreate() {
        super.onCreate();
        Debug.startMethodTracing("tudu");
        initSdk();
        Debug.stopMethodTracing();
    }

        写好上述两行代码后,运行我们的app,即可生成trace文件。生成文件的路径:Android/data/packagename/file,记得在运行后刷新一下:

        双击打开trace文件,进入TraceView主界面:

(1)最上面浅蓝色区域:就是我们选取抓trace文件的起止时间段

(2)THREADS:显示当前所有的线程,后面的长条是耗时

(3)下面的四个tab,可以显示方法及所耗时间,不同的tab有不同的作用,主要介绍Call Chart和Top Down:

Call Chart:

        大家可以发现颜色不一样,这个颜色是有讲究的:绿色的就是我们自己写的方法,蓝色的是系统的方法。

Top Down:

        在我的测试app中,我写了四个方法模拟sdk初始化(均让主线程休眠一段时间),这四个方法又放在了initSdk中,通过这个tab,我们可以很清晰的看到各个方法的耗时。

六、启动优化

        在这个章节中,介绍几种启动优化的技巧。当然,我是以一个demo项目来介绍,这与我们实际的项目开发过程中会有点不同。但是,基本的思路是一样的。不知道大家有没有遇到测试提过如下问题:应用启动白屏(或黑屏时间)太久,希望优化。这个启动白屏(黑屏)时间太久,就是我们启动优化要做的工作。

1、闪屏

        什么是闪屏?上面我们提到过,在application启动前,系统会创建一个空白的window,而我们的闪屏,就是在这个空白的window上做文章。

        首先,我们看一下优化之前,我的demo运行效果,如下图所示。可以看到,点击图标启动app后,有2秒多的白屏时间。当然,这个是因为我在代码中动了手脚,在Application中模拟耗时操作2秒钟。

        接下来,我们操作一下,如何通过闪屏来优化这个体验:

       (1)我们在drawable中创建一个drawable,命名为splash_bg:



        (2)自定义Theme,并且在Manifest中为我们的MainActivity配置好:


    
        @drawable/splash_bg
    


        

 (3)在MainActivity的onCreate中,手动把Theme修改为我们原有的Theme:


protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        setContentView(R.layout.activity_main);
    }

        我们看一下优化后的效果,是不是给人一种秒开的错觉?对,实际上,我们只是把原来的白屏替换为我们自己定义的一个drawable,并且在activity的onCreate中,再替换为正确的Theme。但,这样会让用户更好去接受。

 

2、异步优化

        先简单的介绍一下异步优化,异步优化,顾名思义,就是把线性执行的操作改为异步执行。例如,我们在主线程中做了2000ms的耗时操作。假如我们创建几个子线程,让子线程同步去进行sdk初始化等耗时操作。当然,为了比较优雅的实现多线程,我们简单的使用一下线程池。


private void initSdkWithThreadPool(){
        ExecutorService service = Executors.newFixedThreadPool(CORE_POOL_SIZE);
        service.submit(new Runnable() {
            @Override
            public void run() {
                initSdk1();
            }
        });
        service.submit(new Runnable() {
            @Override
            public void run() {
                initSdk2();
            }
        });
        service.submit(new Runnable() {
            @Override
            public void run() {
                initSdk3();
            }
        });
        service.submit(new Runnable() {
            @Override
            public void run() {
                initSdk4();
            }
        });
    }

         我们看一下这样做后的优化效果:

        看到上面的优化结果,大家是不是非常开心?是不是觉得不管有多少个耗时操作,我们都可以使用线程池异步来加载,就能达到上面秒开的效果?不好意思,答案是否定的。在很多情况下,我们是不能简单地使用线程池来达到我们的优化目的的。那么,什么情况呢?答案就是,我们的某些操作必须要在主线程中进行或者我们必须在主线程中用到该操作的某个产物。

        针对上面的答案,可能有些朋友不太明白。我举个简单的例子,我们要在splash界面使用initSdk1方法的某个产物,而由于是异步执行,很有可能我们需要这个产物的时候,InitSdk1方法尚未执行完成。那这样的情况下,肯定会得到我们不想要的结果。例如,我们的initSdk1方法会给我们返回一个String值,而我们会通过Toast展示这个字符串,如下:


private String initSdk1() {
        try {
            //模拟sdk初始化等耗时操作
            Thread.sleep(500);
            result = "sdk1 init success";
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mCountDownLatch.countDown();
        return result;
    }

        如果我们异步执行,并且在异步方法后面去打印Toast,那么肯定拿不到“sdk1 init success”,拿到的是null,这样是不对的。那么,initSdk1这个方法我们就不让他异步执行了。我们单独把他拿出来,让他执行完后,我们再去打印我们的Toast。


initSdk1();
initSdkWithThreadPool();
Toast.makeText(this, result, Toast.LENGTH_SHORT).show();

        这篇文章总结了app启动优化的一些知识,包括启动的几种方式,获取启动时间以及启动优化用到的一个性能分析工具TraceView,并且通过一个简单的demo总结了两种启动优化的方法:闪屏和异步优化。其实闪屏和异步优化只是启动优化的最常规方式,相信很多一线团队都有自己的一些启动优化的独门秘笈。


作者:heart荼毒


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android性能优化(一)启动优化

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android性能优化(一)启动优化

以前做手机的时候,我非常重视app的性能优化。其实一直以来,在工作中我总会去强调性能优化的重要性。但是,很多时候,由于一些外界因素,我们对app的一些性能指标不会那么重视。但是,性能优化依然是做好一个产品的重中之重。试想一下,如果用户费了很
2022-06-06

Android性能优化(一)App启动时间优化

App启动时间优化 一、首先我们需要清楚App的主题加载 你的App的主题位于 res/values/styles我们点击Light主题进去,会发现此主题位于 app/build/intermediates/exploded-oar/com
2022-06-06

抖音 Android 性能优化系列:启动优化实践

本篇我们将按照主线程直接优化、后台线程间接优化、全局优化的逻辑,介绍团队在启动优化的实践中遇到的一些比较典型的案例,其间对于业界一些比较优秀的方案也会进行简要介绍。

Android启动优化

一、启动分类 Android的启动分冷启动、热启动、温启动。 1、冷启动:当启动应用时,后台没有这个应用的进程,需创建新的进程。 冷启动过程: click (点击应用图标)——>ipc——>Process.start——>ActivityT
2022-06-06

Android性能优化之网络优化

在移动互联网的快速发展环境下,手机用户日益对网络的使用或体验有着更深度的诉求,因此应用中的网络体验已经显得由此重要。

Android性能优化系列篇UI优化

这篇文章主要为大家介绍了Android性能优化系列篇UI优化示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Android 性能优化 ~ 包体积优化实战

概述 用户通常都不愿意去下载一个比较大的程序,特别是不在 WIFI 的情况下。如果你的安装包很小,用户还是愿意下载安装体验下的。现在市面上满足某种需求的 App 通常都会有很多款,如何让用户愿意下载你的 App 来体验?安装包越小,在 WI
2022-06-06

android性能优化之启动过程的示例分析

小编给大家分享一下android性能优化之启动过程的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、应用的启动方式通常来说,启动方式分为两种:冷启动和热
2023-05-30

Android性能优化之弱网优化详解

这篇文章主要为大家介绍了Android性能优化之弱网优化示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Android性能优化方法

GPU过度绘制 打开开发者选型,“调试GPU过度绘制”,蓝、绿、粉红、红,过度绘制依次加深 粉红色尽量优化,界面尽量保持蓝绿颜色 红色肯定是有问题的,不能忍受使用HierarchyView分析布局层级 删除多个全屏背景:应用中不可见
2022-06-06

Android性能优化以及数据优化方法

Android性能优化-布局优化 今天,继续Android性能优化 一 编码细节优化。 编码细节,对于程序的运行效率也是有很多的影响的。今天这篇主题由于技术能力有限,所以也不敢在深层去和大家分享。我将这篇主题分为以下几个小节: (1)缓存
2022-06-06

抖音 Android 性能优化系列:Java 锁优化

本文将着重向大家介绍 Slardar 线上锁监控方案的原理与使用方法,以及我们在抖音上发现的锁的经典案例与优化实践。

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录