浅谈android性能优化之启动过程(冷启动和热启动)

本文介绍了浅谈android性能优化之启动过程(冷启动和热启动) ,分享给大家,具体如下:

一、应用的启动方式

通常来说,启动方式分为两种:冷启动和热启动。

1、冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动。

2、热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。

特点

1、冷启动:冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。

2、热启动:热启动因为会从已有的进程中来启动,所以热启动就不会走Application这步了,而是直接走MainActivity(包括一系列的测量、布局、绘制),所以热启动的过程只需要创建和初始化一个MainActivity就行了,而不必创建和初始化Application,

因为一个应用从新进程的创建到进程的销毁,Application只会初始化一次。

二、应用的启动过程

冷启动启动流程:当点击app的启动图标时,安卓系统会从Zygote进程中fork创建出一个新的进程分配给该应用,之后会依次创建和初始化Application类、创建MainActivity类、加载主题样式Theme中的        

windowBackground等属性设置给MainActivity以及配置Activity层级上的一些属性、再inflate布局、当onCreate/onStart/onResume方法都走完了后最后才进行contentView的measure/layout/draw显示在界面上,所以直到这里,

应用的第一次启动才算完成,这时候我们看到的界面也就是所说的第一帧。所以,总结一下,应用的启动流程如下:

Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>测量布局绘制显示在界面上。

大致流程如下:

1、点击桌面图标,Launcher会启动程序默认的Acticity,之后再按照程序的逻辑启动各种Activity

2、启动Activity都需要借助应用程序框架层的ActivityManagerService服务进程(Service也是由ActivityManagerService进程来启动的);在Android应用程序框架层中,ActivityManagerService是一个非常重要的接口,

它不但负责启动Activity和Service,还负责管理Activity和Service。

Step 1. 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManagerService.startActivity接口;

Step 2. ActivityManagerService调用ActivityStack.startActivityMayWait来做准备要启动的Activity的相关信息;

Step 3. ActivityStack通知ApplicationThread要进行Activity启动调度了,这里的ApplicationThread代表的是调用ActivityManagerService.startActivity接口的进程,对于通过点击应用程序图标的情景来说,这个进程就是Launcher了,

而对于通过在Activity内部调用startActivity的情景来说,这个进程就是这个Activity所在的进程了;

Step 4. ApplicationThread不执行真正的启动操作,它通过调用ActivityManagerService.activityPaused接口进入到ActivityManagerService进程中,看看是否需要创建新的进程来启动Activity;

Step 5. 对于通过点击应用程序图标来启动Activity的情景来说,ActivityManagerService在这一步中,会调用startProcessLocked来创建一个新的进程,而对于通过在Activity内部调用startActivity来启动新的Activity来说,这一步是不需要执行的,

因为新的Activity就在原来的Activity所在的进程中进行启动;

Step 6. ActivityManagerServic调用ApplicationThread.scheduleLaunchActivity接口,通知相应的进程执行启动Activity的操作;

Step 7. ApplicationThread把这个启动Activity的操作转发给ActivityThread,ActivityThread通过ClassLoader导入相应的Activity类,然后把它启动起来。

三、冷启动过程中碰到的白屏黑屏以及优化启动时间

1、白屏问题 :

android studio升级 2.0之后 加上Instant Run,Instant Run为了能够让我们快速部署代码,背后其实是有一套非常复杂的逻辑的,比如要在APK中建立服务器与Android Studio进行通信,以及代码差异比对和替换等,在研发过程中可能出现白屏问题,

一般release版的程序是不会出现这种现象的;

如果接下来还会出现白屏问题,可以查看style文件

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
......
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
</style> 

加入了两个属性,windowIsTranslucent和windowNoTitle,将这两个属性都设置成true,就可以让程序在初始化的时候窗口是透明的,初始化结束后程序主界面才会显示出来,从而也就完全看不到白屏界面了

2、启动时间的优化

先测量activity的启动时间-------Activity的reportFullyDrawn()方法

你就需要调用Activity的reportFullyDrawn()。它将在log里报告从apk初始化(和前面Displayed的时间是一样的)到reportFullyDrawn() 方法被调用用了多长时间。

reportFullyDrawn()方法显示的log也是类似这样:

ActivityManager: Displayed com.Android.myexample/.StartupTiming: +768ms

在4.4上调用reportFullyDrawn()方法会崩溃(但是log还是能正常打印),提示需要UPDATE_DEVICE_STATS权限 ,但是这个权限只有系统app才能授权。解决的办法是这样调

 try{

  reportFullyDrawn();

  }catch(SecurityException e){

  }

还有一种测量启动时间的方法也值得一提,那就是screenrecord命令

首先启动带—bugreport选项(它可以在frames 中添加时间戳-应该是L中的特性)的screenrecord 命令:

$ adb shell screenrecord --bugreport /sdcard/launch.mp4

然后点击app的图标,等待app显示,ctrl-C screenrecord, 使用adb pull命令把文件导出到电脑。

$ adb pull /sdcard/launch.mp4

现在你可以打开录制视频看看发生了什么。你需要一个能逐帧查看的视频播放器(mac上的Quicktime 就可以,不清楚其它os上什么播放器这个功能最好使)。现在逐帧播放,注意视频的上方有一个frame 时间戳。

一直往前直到你发现app图标高亮了为止。这个时候系统已经处理了图标上的点击事件,开始启动app了,记录下这一帧的时间。继续播放帧直到你看到了app整个UI的第一帧为止。根据不同情况(是否有启动窗口,是否有启动画面等等),

事件和窗口发生的实际顺序可能会有不同。对于一个简单的app来说,你会首先见到启动窗口,然后渐变出app真实的UI。在你看到UI上的任何内容之后,你应该记录下第一帧,这时app完成了布局和绘制,准备开始显示出来了。同时也记录下这一帧所发生的时间。

现在把这两个时间相减 ((UI displayed) - (icon tapped)); 得到app从点击到绘制就绪的所有时间。虽然这个时间包含了进程启动之前的时间,但是至少它可以用于跟其他app比较。

Android冷启动时间优化

冷启动时间是指当用户点击你的app那一刻到系统调用Activity.onCreate()之间的时间段。在这个时间段内,WindowManager会先加载app主题样式中的windowBackground做为app的预览元素,然后再真正去加载activity的layout布局

冷启动时间优化

知道了Android冷启动时间的原理之后,就可以通过一些小技巧来对冷启动时间进行优化,从而让你app加载变得”快“一些(视觉体验上的快)。我们可制作一个启动Activity的背景样式的.9图片,然后把这个.9图片做为windowBackground。

图片制作好之后,我们就可以用它做为app冷启动阶段的预览元素,如下设置:

为启动的Activity自定义一个Theme

<style name="AppTheme.Launcher">

  <item name="android:windowBackground">@drawable/window_background_statusbar_toolbar_tab</item>

</style>

将新的Theme应用到设置到AndroidManifest.xml中

<activity

  android:name=".MainActivity"

  android:theme="@style/AppTheme.Launcher">

  <intent-filter>

    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />

  </intent-filter>

</activity>

由于给MainActivity设置了一个新的Theme,这样做会覆盖原来的Theme,所以在MainActivity中需要设置回原来的Theme

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {

    // Make sure this line comes before calling super.onCreate().
    setTheme(R.style.AppTheme);

    super.onCreate(savedInstanceState);
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解Android冷启动实现APP秒开的方法

    一.前言 在阅读这篇文章之前,首先需要理解几个东西: 1.什么是Android的冷启动时间? 冷启动时间是指用户从手机桌面点击APP的那一刻起到启动页面的Activity调用onCreate()方法之间的这个时间段. 2.在冷启动的时间段内发生了什么? 首先我们要知道当打开一个Activity的时候发生了什么,在一个Activity打开时,如果该Activity所属的Application还没有启动,那么系统会为这个Activity创建一个进程(每创建一个进程都会调用一次Application,

  • Android冷启动实现app秒开的实现代码

    本文介绍了Android冷启动实现app秒开的实现代码,分享给大家,具体如下: AndroidManifest里对应activity添加属性android:theme="@style/AppSplash" <activity android:name="com.senyint.edu.college.stu.view.activity.SplashActivity" android:screenOrientation="portrait"

  • 浅谈android性能优化之启动过程(冷启动和热启动)

    本文介绍了浅谈android性能优化之启动过程(冷启动和热启动) ,分享给大家,具体如下: 一.应用的启动方式 通常来说,启动方式分为两种:冷启动和热启动. 1.冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动. 2.热启动:当启动应用时,后台已有该应用的进程(例:按back键.home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热

  • 浅谈Android性能优化之内存优化

    1.Android内存管理机制 1.1 Java内存分配模型 先上一张JVM将内存划分区域的图 程序计数器:存储当前线程执行目标方法执行到第几行. 栈内存:Java栈中存放的是一个个栈帧,每个栈帧对应一个被调用的方法.栈帧包括局部标量表, 操作数栈. 本地方法栈:本地方法栈主要是为执行本地方法服务的.而Java栈是为执行Java方法服务的. 方法区:该区域被线程共享.主要存储每个类的信息(类名,方法信息,字段信息等).静态变量,常量,以及编译器编译后的代码等. 堆:Java中的堆是被线程共享的,

  • 详解Android性能优化之启动优化

    1.为什么要进行启动优化 网上流行一种说法,就是8秒定律,意思是说,如果用户在打开一个页面,在8秒的时间内还没有打开,那么用户大概的会放弃掉,意味着一个用户的流失.从这里就可以看出,启动优化的重要性了. 2.启动的分类 2.1 冷启动 先来看看冷启动的流程图 从图中可以看出,APP启动的过程是:ActivityManagerProxy 通过IPC来调用AMS(ActivityManagerService),AMS通过IPC启动一个APP进程,ApplicationThread通过反射来创建App

  • 浅谈PHP性能优化之php.ini配置

    内存 默认设置 memory_limit = 128M 单个进程可使用的内存最大值,这个值的设定可以从以下几点考虑: 应用的类型.如果是内存集中型应用,可增加该值: 单个 PHP 进程平均消耗的内存,该值可通过多次运行同一个脚本来计算平均值: 能负担多少个 php-fpm 进程:该值等于分配的总内存除以单个 PHP 进程平均消耗的内存: 文件上传 默认设置 file_uploads = On max_file_uploads = 20 upload_max_filesize = 2M max_e

  • 浅谈Android ANR的信息收集过程

    目录 一. ANR场景 二. appNotResponding处理流程 三. 总结 一. ANR场景 无论是四大组件或者进程等只要发生ANR,最终都会调用AMS.appNotResponding()方法,下面从这个方法说起. 以下场景都会触发调用AMS.appNotResponding方法: Service Timeout:比如前台服务在20s内未执行完成: BroadcastQueue Timeout:比如前台广播在10s内未执行完成 InputDispatching Timeout: 输入事

  • 浅谈react性能优化的方法

    React性能优化思路 软件的性能优化思路就像生活中去看病,大致是这样的: 使用工具来分析性能瓶颈(找病根) 尝试使用优化技巧解决这些问题(服药) 使用工具测试性能是否确实有提升(疗效确认) 初识react只是为了尽快完成项目,后期进行代码审查时候发现有很多地方需要优化,因此做了个小结. Code Splitting shouldComponentUpdate避免重复渲染 使用不可突变数据结构 组件尽可能的进行拆分.解耦 列表类组件优化 bind函数优化 不要滥用props ReactDOMSe

  • 浅谈Vue 性能优化之深挖数组

    背景 最近在用 Vue 重构一个历史项目,一个考试系统,题目量很大,所以核心组件的性能成为了关注点.先来两张图看下最核心的组件 Paper 的样式. 从图中来看,分为答题区与选择面板区. 稍微对交互逻辑进行下拆解: 答题模式与学习模式可以相互切换,控制正确答案显隐. 单选与判断题直接点击就记录答案正确性,多选是选择答案之后点击确定才能记录正确性. 选择面板则是记录做过的题目的情况,分为六种状态(未做过的,未做过且当前选择的,做错的,做错的且当前选择的,做对的,做对的且当前选择的),用不同的样式去

  • 浅谈Android插件化

    目录 一.认识插件化 1.1 插件化起源 1.2 插件化优点 1.3 与组件化的区别 二.插件化的技术难点 三.ClassLoader Injection 3.1 java 中的 ClassLoader 3.2 android 中的 ClassLoader 3.3 双亲委派机制 3.4 如何加载插件中的类 3.5 执行插件类的方法 四.Runtime Container 4.1 为什么没有注册的 Activity 不能和系统交互 4.2 运行时容器技术 4.3 字节码替换 五.Resource

  • 浅谈android获取设备唯一标识完美解决方案

    本文介绍了浅谈android获取设备唯一标识完美解决方案,分享给大家,具体如下: /** * deviceID的组成为:渠道标志+识别符来源标志+hash后的终端识别符 * * 渠道标志为: * 1,andriod(a) * * 识别符来源标志: * 1, wifi mac地址(wifi): * 2, IMEI(imei): * 3, 序列号(sn): * 4, id:随机码.若前面的都取不到时,则随机生成一个随机码,需要缓存. * * @param context * @return */ p

随机推荐