Android性能优化干货分享;你的 APP 为何启动那么慢?

简介: App启动方式冷启动(Cold start)冷启动是指APP在手机启动后第一次运行,或者APP进程被kill掉后在再次启动。

App启动方式

冷启动(Cold start)

冷启动是指APP在手机启动后第一次运行,或者APP进程被kill掉后在再次启动。
可见冷启动的必要条件是该APP进程不存在,这就意味着系统需要创建进程,APP需要初始化。在这三种启动方式中,冷启动耗时最长,对于冷启动的优化也是最具挑战的。因此本文重点谈论的是对冷启动相关的优化。

温启动(Warm start)

App进程存在,当时Activity可能因为内存不足被回收。这时候启动App不需要重新创建进程,但是Activity的onCrate还是需要重新执行的。场景类似打开淘宝逛了一圈然后切到微信去聊天去了,过了半小时再次回到淘宝。这时候淘宝的进程存在,但是Activity可能被回收,这时候只需要重新加载Activity即可。

热启动(Hot start)

App进程存在,并且Activity对象仍然存在内存中没有被回收。可以重复避免对象初始化,布局解析绘制。
场景就类似你打开微信聊了一会天这时候出去看了下日历 在打开微信 微信这时候启动就属于热启动。

在最近任务给App加锁和启动方式有什么关系

某些厂商为了用户体验提供了给APP上锁的功能,目的就是让用户自己做主是上锁的APP不被杀,启动的时候不会处于冷启动方式,但是加锁也不是万能的,Low memory killer在内存极度吃紧的情况下也会杀死加锁APP,在此启动时也将以冷启动方式运行。

AI和启动方式有什么关系

AI在进程管理方面可谓是大有可为。MIUI10发布了进程AI唤醒功能,使APP启动速度远超友商。这其中的道理简单说就是学习用户的使用习惯,提前将App进程创建好,当用户打开APP时不会出现冷启动。比如你是微信重度用户你发现用了MIUI10就再也见不到微信启动页面的那个地球了,这就是AI唤醒的功劳。

从点击APP图标到主页显示出现需要经过的步骤

这里我们来讨论冷启动的过程,进程启动原则上有四种途径,也就是通过其他进程对该APP的四大组件的调用来实现。

这里我们重点讨论用户点击桌面后的APP启动,通过startActivity方式的启动。
调用startActivity,该方法经过层层调用,最终会调用ActivityStackSupervisor.java中的startSpecificActivityLocked,当activity所属进程还没启动的情况下,则需要创建相应的进程.

void startSpecificActivityLocked(...) {
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);
    if (app != null && app.thread != null) {
         ...//进程已创建
        return
    }
    //创建进程
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
}

最终进程由 Zygote Fork进程:

进程启动后系统还有一个工作就是:进程启动后立即显示应用程序的空白启动窗口。

一旦系统创建应用程序进程,应用程序进程就会负责下一阶段。这些阶段是:

1.创建应用程序对象

2.启动主线程

3.创建主要Activity

4.绘制视图(View)

5.布局屏幕

6.执行初始化绘制

而一旦App进程完成了第一次绘制,系统进程就会用Main Activity替换已经展示的Background Window,此时用户就可以使用App了。

 

这里很明显有两个优化点:

1.Application OnCrate()优化

当APP启动时,空白的启动窗口将保留在屏幕上,直到系统首次完成绘制应用程序。此时,系统进程会交换应用程序的启动窗口,允许用户开始与应用程序进行交互。如果应用程序中重载了Application.onCreate(),系统会调用onCreate()方法。之后,应用程序会生成主线程(也称为UI线程),并通过创建MainActivity来执行任务。

2.Activity onCreate()优化

onCreate()方法对加载时间的影响最大,因为它以最高的开销执行工作:加载并绘制视图,以及初始化Activity运行所需的对象。

启动速度优化

如何对启动时间进行量化?

1.目前为止见过最最牛逼的是使用机械手和高速相机测试,手机开机后使用机械手点击应用桌面图标,高速相机记录启动过程,后续通过程序分析视频,从机械手点击图标到Activity显示出来使用了多少时间。这种方式是最直观和精确的,但是成本也很高。

2.通过shell 命令

adb shell am start -W [packageName]/[packageName.MainActivity]

执行成功后将返回三个测量到的时间:

ThisTime:一般和TotalTime时间一样,除非在应用启动时开了一个透明的Activity预先处理一些事再显示出主Activity,这样将比TotalTime小。

TotalTime:应用的启动时间,包括创建进程+Application初始化+Activity初始化到界面显示。

WaitTime:一般比TotalTime大点,包括系统影响的耗时。

3.可以通过在代码中增加log来计算启动时间

4.使用systrace

Application OnCrate()优化

1.第三方SDK初始化的处理

Application是程序的主入口,很多三方SDK示例程序中都要求自己在Application OnCreate时做初始化操作。这就是增加Application OnCreate时间的主要元凶,所以需要尽量避免在Application onCreate时同步做初始化操作。比较好的解决方案就是对三方SDK就行懒加载,不在Application OnCreate()时初始化,在真正用到的时候再去加载。

下面实例对比下ImageLoader在采用懒加载后启动速度优化。

一般我们在使用imageLoader时都会在Application onCreate()时在主线程加载:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ImageLoaderConfiguration.Builder config =
                new ImageLoaderConfiguration.Builder(this);
        ImageLoader.getInstance().init(config.build());
    }
}

此时使用adb shell am start -W [packageName]/[packageName.MainActivity]检测应用启动时间,每次执行命令时需要杀死进程。

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.luozhanwei.myapplication/.MainActivity }
Status: ok
Activity: com.luozhanwei.myapplication/.MainActivity
ThisTime: 423
TotalTime: 423
WaitTime: 441

Total time在423ms之间,下面是封装了一个懒加载ImageLoader的工具类示例:

public class ImageUtil {

    private static boolean sInit;

    private synchronized static void ensureInit() {
        if (sInit) {
            return;
        }
        ImageLoaderConfiguration.Builder config =
                new ImageLoaderConfiguration.Builder(SecurityCoreApplication.getInstance());
      ....
        // Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(config.build());
        sInit = true;
    }

public static void display(String uri, ImageView imageView, boolean cacheOnDisk) {
        imageView.setImageResource(R.drawable.icon_app_default);
        ensureInit();
        ImageLoader loader = ImageLoader.getInstance();
        if (cacheOnDisk) {
            loader.displayImage(uri, imageView);
        } else {
            loader.displayImage(uri, imageView, OPTIONS_NO_CACHE_DISK);
        }
    }

使用这种方案后的启动时间:

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.luozhanwei.myapplication/.MainActivity }
Status: ok
Activity: com.luozhanwei.myapplication/.MainActivity
ThisTime: 389
TotalTime: 389
WaitTime: 405

看到TotalTime比之前减少了34ms(给出的数据为10次检测平均值)。

所以Application OnCreate 避免在主线程做大量耗时操作,例如和IO相关的逻辑,这样都会影响到应用启动速度。如果必须要做需要放到子线程中。

Activity onCreate()优化

减少LaunchActivity的View层级,减少View测量绘制时间。
避免主线程做耗时操作

用户体验优化

消除启动时的白屏/黑屏

为什么启动时会出现短暂黑屏或白屏的现象?当用户点击你的app那一刻到系统调用Activity.onCreate()之间的这个时间段内,WindowManager会先加载app主题样式中的windowBackground做为app的预览元素,然后再真正去加载activity的layout布局。

很显然,如果你的application或activity启动的过程太慢,导致系统的BackgroundWindow没有及时被替换,就会出现启动时白屏或黑屏的情况(取决于你的主题是Dark还是Light)。

 

解决方案

1.甩锅给系统

使用透明主题:

<item name="android:windowIsTranslucent">true</item>

Activity.onCreate()之前App不做显示,这样用户误以为是手机慢了,这种瞒天过海的方案大家还是不要用了。

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>

</resources>

效果如下:

2.主题替换
我们在style中自定义一个样式Lancher,在其中放一张背景图片,或是广告图片之类的

<style name="AppTheme.Launcher">
        <item name="android:windowBackground">@drawable/bg</item>
    </style>

把这个样式设置给启动的Activity

<activity
            android:name=".activity.SplashActivity"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.Launcher"
            >

然后在Activity的onCreate方法,把Activity设置回原来的主题

@Override
    protected void onCreate(Bundle savedInstanceState) {
        //替换为原来的主题,在onCreate之前调用
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
    }

这样在启动时就通过给用户看一张图片或是广告来防止黑白屏的尴尬。

附录;

Android高级工程师技术大纲和系统进阶视频资料

 

 

 

免费获取方式;

加Android高级进阶群,701740775。进群可免费领取一份最新技术大纲和Android进阶资料。请备注csdn

相关文章
|
1月前
|
算法 数据处理 Android开发
掌握安卓性能优化的秘诀:电池寿命与运行效率的提升
【10月更文挑战第6天】 本文深入探讨了安卓应用开发中的性能优化技巧,重点分析了影响电池寿命和运行效率的关键因素,并提供了针对性的优化策略。通过代码优化、资源管理、后台任务处理等方法,开发者可以显著提升应用的续航能力和流畅度。同时,结合具体案例,展示了如何在实际开发中应用这些技巧,确保应用在各种场景下都能保持高效运行。本文旨在为安卓开发者提供实用的性能优化指导,助力其打造更优质的应用体验。
44 2
|
1月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
140 0
安卓项目:app注册/登录界面设计
|
9天前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
14天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
28 5
|
14天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
33 3
|
1月前
|
存储 缓存 网络协议
5个Android性能优化相关的深度面试题
本文涵盖五个Android面试题及其解答,包括优化应用启动速度、内存泄漏的检测与解决、UI渲染性能优化、减少内存抖动和内存溢出、优化网络请求性能。每个问题都提供了详细的解答和示例代码。
26 2
|
1月前
|
监控 测试技术 Android开发
掌握安卓性能优化的关键策略
【10月更文挑战第7天】 在移动应用开发领域,性能优化是一项至关重要的任务。本文将探讨安卓应用性能优化的重要性、关键策略以及实际操作建议,帮助开发者提升应用的用户体验和竞争力。通过深入浅出的方式,我们将从背景介绍到具体实践,全面解析安卓性能优化的各个维度。
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
121 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
2月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
159 2
|
2月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
103 3

热门文章

最新文章