一篇文章搞定《APP的启动流程》

这篇具有很好参考价值的文章主要介绍了一篇文章搞定《APP的启动流程》。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

前面已经铺垫了Binder、Handler、View的绘制流程
那么该来看看APP的启动流程了,是如何启动了我们这些重要的组件
本文会按照步骤和启动需要的成员并附带一点点源码进行讲解。
以了解熟悉启动的流程为主。不会大篇幅的利用源码深入。
本文结构:
1、冷启动、温启动、热启动
2、启动中的重要成员简介
3、启动的步骤详解
4、启动优化(浅谈)

冷启动、温启动、热启动

  • 冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,然后再根据启动的参数,启动对应的进程组件,这个启动方式就是冷启动。
  • 温启动:当启动应用时,后台已有该应用的进程,但是Activity可能因为内存不足被回收。这样系统会从已有的进程中来启动这个Activity,这个启动方式叫温启动。
  • 热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动对应的进程组件,这个方式叫热启动。

由于冷启动相对于其他启动方式多了进程的创建(Zygote进程fork创建进程)以及应用的资源加载和初始化(Application的创建及初始化),所以相对来说会比较耗时,所以我们一般说的App启动优化一般指的都是App的冷启动优化。
启动中的重要

启动中的重要成员简介

zygote进程

不说的冠冕堂皇的,就简单的给大家总结两条:

  • zygote进程是由Linux中的init进程,fock出来的进程。
  • 在Android中,所有的应用的进程都是由zygote进程fork出来的,一个新的App进程就是zygote进程的子进程。

Zygote进程首先会fork自己孵化出的SystemServer进程,它的main函数主要负责:

  • 启动binder线程池,这是SystemServer与其他进程通信的基础
  • 初始化Looper
  • 创建了SystemServiceManager对象,它会启动Android中的各种服务。包括AMS、PMS、WMS
  • 启动桌面进程,这样才能让用户见到手机的界面。
  • 开启loop循环,开启消息循环,SystemServer进程一直运行,保障其他应用程序的正常运行。

注意:init进程在开启的时候就创建了,所以在开机的时候我们的zygote进程和ServiceManager都被创建出来了。

Instrumentation

工具类,它用来监控应用程序和系统的交互,包装了 ActivityManagerService 的调用,一些插件化方案就是通过 hook 该类实现的。

SystemServer进程

SystemServer是由zygote进程fork出来的第一个进程,SystemServer和Zygote是Android Framework最重要的2个进程。 系统里面重要的服务都是在这个进程里面开启的,比如ActivityManagerService、PackageManagerService、WindowManagerService。
应用启动流程基本是围绕着ActivityManagerService和ActivityThread展开。

ActivityManagerService

  • 在Android系统中,任何一个Activity的启动都是由AMS和App进程(主要是ActivityThread)相互配合来完成的。
  • 他在SystemServer创建后被初始化
  • App进程与AMS通过Binder机制进行跨进程通信
  • AMS(SystemServer进程)与zygote通过Socket进行跨进程通信。

Binder

Binder就不细说了,Android系统中的IPC跨进程通信。
就是《一篇文章搞定〈Binder〉》中的内容

ActivityThread

ActivityThread 是 Android 系统中驱动应用程序的主线程,它的作用是管理应用程序的生命周期和交互。ActivityThread 负责启动应用程序的入口 Activity,提供与 Android 系统之间的通信桥梁,同时也处理了应用程序的消息队列和事件循环。
在 App 启动过程中,ActivityThread 主要负责以下几个重要的工作:

  • 创建一个主线程 Looper ,用于处理消息队列和事件循环。
  • 加载应用程序的主题、资源和布局文件。
  • 通过调用 Instrumentation 的 callApplicationOnCreate() 方法触发应用程序的生命周期,初始化应用程序,并创建首个 Activity。

启动的步骤详解

图中的红色线条为Binder通信
紫色线条是Socket通信

一、点击桌面图标

  • Launcher 捕获点击事件,调用 Activity#startActivity();
  • 点击图标发生在Launcher应用的进程,startActivity()函数最终是由Instrumentation通过Android的Binder跨进程通信机制 发送消息给 system_server 进程;
    一篇文章搞定《APP的启动流程》,Android,一篇文章搞定Android,android,java

二、创建进程

在 system_server 中,启动进程的操作会先调用ActivityManagerService#startProcessLocked() 方法,该方法内部调用 Process.start(android.app.ActivityThread);而后通过 socket 通信告知 Zygote 进程 fork 子进程,即 app 进程。
一篇文章搞定《APP的启动流程》,Android,一篇文章搞定Android,android,java

三、初始化APP进程

  • 开启主线程 app 进程启动后,首先是实例化 ActivityThread,并执行其main()函数
  • main()函数中创建 ApplicationThread,Looper,Handler 对象,并开启主线程消息循环Looper.loop()。
  • 调用 ActivityThread#attach(false)方法进行 Binder 通信

源码如下:ActivityThread.java

public static void main(String[] args) {
···
     Looper.prepareMainLooper();

     ActivityThread thread = new ActivityThread();
     thread.attach(false);

     if (sMainThreadHandler == null) {
         sMainThreadHandler = thread.getHandler();
     }
 ···
     Looper.loop();
 ···
 }


 private void attach(boolean system) {
 ···
     if (!system) {
     ···
         final IActivityManager mgr = ActivityManager.getService();
         try {
             mgr.attachApplication(mAppThread);
         } catch (RemoteException ex) {
             throw ex.rethrowFromSystemServer();
         }
     ···
     } else {
    ···
     }
 ···
 }

一篇文章搞定《APP的启动流程》,Android,一篇文章搞定Android,android,java

四、APP进程与System_server的绑定

  • 调用 ActivityThread#attach(false)方法进行 Binder 通信(在方法里进行下一步)
  • 通知system_server进程执行 ActivityManagerService#attachApplication(mAppThread)方法
  • system_server进程在收到请求后,进行一系列准备工作后(创建该App进程信息表)再通过binder IPC向App进程发送scheduleLaunchActivity请求;
  • 这相当于是APP进程发信息给system_server进程,进行一个绑定的过程。创建通信的过程。
    一篇文章搞定《APP的启动流程》,Android,一篇文章搞定Android,android,java

五、初始化Applacation And Activity

  • App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程(ActivityThread)发送LAUNCH_ACTIVITY消息;
  • 主线程(ActivityThread)在收到Message后,通过HandleLaunchActivity创建目标Activity,并回调Activity.onCreate()等方法。
  • 到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面
    一篇文章搞定《APP的启动流程》,Android,一篇文章搞定Android,android,java
    到此为止App的启动流程就结束了,上图也是完整的启动流程模型图。

启动优化(浅谈)

透明主题优化

为了解决启动窗口白屏问题,使用透明主题来解决这个问题,但是治标不治本。

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

设置闪屏图片主题

这个挺多APP还在用的哦
为了更顺滑无缝衔接我们的闪屏页,可以在启动 Activity 的 Theme中设置闪屏页图片,这样启动窗口的图片就会是闪屏页图片,而不是白屏。

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowBackground">@mipmap/launch_image</item>   //闪屏页图片  
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>
</style>

这样设置的话,就会在冷启动的时候,展示闪屏页的图片,等App进程初始化加载入口 Activity (也是闪屏页) 就可以无缝衔接。
其实这种方式并没有真正的加速应用进程的启动速度,而只是通过用户视觉效果带来的优化体验。

Application 优化

通过上面的流程,我们可以知道。会先初始化我们的Application,所以在Application中初始化减少耗时操作能有效的帮我提升。
通常,有机会优化这些工作以实现性能改进,这些常见问题包括:

  • 复杂繁琐的布局初始化
  • 阻塞主线程 UI 绘制的操作,如 I/O 读写或者是网络访问.
  • Bitmap 大图片或者 VectorDrawable加载
  • 其它占用主线程的操作

有很多第三方组件(包括App应用本身)都在 Application 中抢占先机,完成初始化操作。
比如Bugly,x5内核初始化,SP的读写,友盟等组件。那就放到子线程中去初始化。

闪屏页业务优化

例如埋点,点击流,数据库初始化等这类必须在主线程初始化的动作。那么我们可以放在闪屏页。
一般:闪屏页政展示总时间 = 组件初始化时间 + 剩余展示时间。
也就是2000ms的总时间,组件初始化了800ms,那么就再展示1200ms即可。

通过上面的流程分析,我们可以知道 Application 初始化后会调用 attachBaseContext() 方法,再调用 Application 的 onCreate(),再到入口 Activity的创建和执行 onCreate() 方法。所以我们就可以在 Application 中记录启动时间。
Application.java

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    SPUtil.putLong("application\_attach\_time",
        System.currentTimeMillis());//记录Application初始化时间  
}

有了启动时间,我们得知道入口的 Acitivty 显示给用户的时间(View绘制完毕)
那就是入口Activity的onWindowFocusChanged喽
入口Activity.java

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    long appAttachTime = SPUtil.getLong("application\_attach\_time");
    long diffTime = System.currentTimeMillis() - appAttachTime;
    //从application到入口Acitity的时间  
    
    //所以闪屏页展示的时间为 2000ms - diffTime.  
}

利用Hook

  • ActivityManagerService

在Android系统中,启动应用的过程通常是通过ActivityManagerService来进行管理的。可以通过Hook ActivityManagerService的方式,在应用启动时进行一些优化操作。例如,可以在应用启动前创建一个空的Activity,并在其onCreate方法中执行一些耗时操作,如初始化数据或预加载资源。然后,通过Hook ActivityManagerService,将启动的Activity替换为这个空的Activity形式,这样就可以减少应用启动的耗时。

  • AMS和PMS

Android系统在应用启动的过程中,会对Activity、Service等组件的启动进行权限验证和安全检查。这个过程较为耗时,可以通过Hook ActivityManagerService(AMS)和PackageManagerService(PMS)来绕过这些检查,从而提升启动速度。例如,可以通过Hook AMS和PMS,修改应用的启动流程,跳过权限验证和安全检查的过程,从而减少启动耗时。

总结

APP的启动流程学问是很大的。需要对Android的源码进行一定的理解。
但是我们在开发中需要有意识的注意会影响APP启动的操作。
毕竟APP的启动是第一扇门。文章来源地址https://www.toymoban.com/news/detail-604914.html

到了这里,关于一篇文章搞定《APP的启动流程》的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【八大排序】一篇文章搞定所有排序

    1.1排序的概念 排序:所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 稳定性:假定在待排序的记录序列中,存在多个具有相同的的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中, r[i]=r[j],且r[i

    2024年04月09日
    浏览(84)
  • 一篇文章搞定克拉美罗界(CRB)

    二郎最近在研究LBL(长基线)定位,大部分论文都提到了文中算法获得的方差接近CRB,所以自己的算法性能较好。于是二郎就想知道克拉美罗界是什么意思,以及能应用的场景。 1)查文档: 克拉美罗界:为无偏估计量的方差确定一个下界,衡量无偏估计的性能。 无偏估计:

    2024年02月15日
    浏览(53)
  • 【Unity】一篇文章搞定AStar(A*)算法

    AStar(A*)算法,是一种在静态网格中求解最短路径直接有效的搜索方法。在游戏开发中,A*算法常应用于部分RPG游戏和策略战棋类游戏。对于Unity开发者来说,掌握A*算法也是十分有必要的。不过在了解A*算法之前,有必要先回顾一下深度优先算法(DFS)、广度优先算法(BFS)

    2024年02月02日
    浏览(58)
  • Android-高级-UI-进阶之路-(五)-看完该篇文章-Canvas-你应该会了

    /** 1. 绘制椭圆 */ canvas.drawOval(RectF(100f,500f,600f,800f),mPaint) /** 2. 绘制圆 */ mPaint.setColor(Color.YELLOW) mPaint.alpha = 100 canvas.drawCircle(400f,400f,200f,mPaint) 绘制 Bitmap // val bitmap = BitmapFactory.decodeResource(context.resources, R.mipmap.gild_3) //第二个,第三个参数代表起点位置 canvas.drawBitmap(bitmap,100f,100

    2024年03月28日
    浏览(57)
  • 一篇文章搞定Java中常用集合的排序方法

    目录 Array · 数组 List · 列表 Collections.sort() 简单类型 复杂对象 类 使用Lambda表达式 Stream API Map · 键值对 对 Map 的 Key 进行排序 对 Map 的 Value 进行排序 最近在做算法题的时候,发现排序在大部分题中都不可或缺,今天心血来潮,总结下Java中集合排序常用的方法,基本覆盖了大

    2024年02月09日
    浏览(55)
  • Spring之AOP(带你一篇文章搞定AOP)

    Spring的核心之一:AOP 用的依赖(包括上篇文章讲诉的IOC依赖): AOP:面向切面编程。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。通俗来说就是在不修改代码的情况下添加新的功能

    2024年02月16日
    浏览(56)
  • 一篇文章搞定什么是nodeJs它和NPM关系与应用

    现在前端的入门门槛越来越高了,不再是单纯 html+css+js ,各种前端框架 层出不穷,各种ui组件库层出不穷。 模块化,打包化,各种工具库层出不穷,前端变成 大前端 ,甚至前端可以搞定整个项目,通过 node 作为服务端api, 这里我们主角就是 nodeJs javaScript是一门脚本语言,

    2024年02月03日
    浏览(48)
  • 一篇文章搞定《动手学深度学习》-(李沐)PyTorch版本的所有内容

    目录 目录 简介 阅读指南 1. 深度学习简介 2. 预备知识 3. 深度学习基础 4. 深度学习计算 5. 卷积神经网络 6. 循环神经网络 7. 优化算法 8. 计算性能 9. 计算机视觉 10. 自然语言处理 环境 参考(大家可以在这里下载代码) 原书地址(大家可以在这里阅读电子版PDF内容) 引用 阅读

    2023年04月24日
    浏览(49)
  • OSPF技术连载16:DR和BDR选举机制,一篇文章搞定!

    你好,这里是网络技术联盟站。 在计算机网络中,开放最短路径优先(Open Shortest Path First,OSPF)是一种广泛使用的内部网关协议(Interior Gateway Protocol,IGP),用于在大型网络中实现路由选择。在OSPF网络中,当一个OSPF区域内有多个路由器时,为了减少链路状态数据库(Link

    2024年02月07日
    浏览(46)
  • 【仿真+实测】一篇文章搞定RC延迟电路 1.延迟开启 2.快速泄放 3.精确泄放

     作者:面向搜索,排版:晓宇 微信公众号:芯片之家(ID:chiphome-dy) RC延迟电路 在许多芯片的应用手册中都要求了 对上电时序进行控制 ,在这种场合下我们会经常看到RC延迟,今天我们通过multisim 14.0 对RC延迟计算电路的理论计算进行仿真验证 Multisim软件版本 附上multisi

    2024年02月09日
    浏览(120)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包