【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | Launcher 应用启用普通安卓应用 | 应用进程分析 )

简介: 【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | Launcher 应用启用普通安卓应用 | 应用进程分析 )

文章目录

一、 Launcher 应用 startActivitySafely 方法分析

二、 Launcher 中的 startActivity(View v, Intent intent, Object tag) 方法分析

三、 Android 应用进程分析



上一篇博客 【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | Launcher 应用简介 | Launcher 应用源码简介 | Launcher 应用快捷方式图标点击方法分析 ) 分析了 Launcher 应用中 Launcher.java 界面代码 , 并分析了图标点击事件 onClick 方法 , 本篇博客继续分析 Launcher 应用中启动普通 Android 应用的源码 ;






一、 Launcher 应用 startActivitySafely 方法分析


在 Launcher 应用中 , 点击快捷方式图标 , 调用 onClick 方法 , 如果判定点击的图标组件时应用图标 , 会触发调用 startActivitySafely 方法 , 启动该图标对应的 Android 应用 Activity 界面 ;


 

boolean startActivitySafely(View v, Intent intent, Object tag) {
        boolean success = false;
        try {
          // 启动新的应用
            success = startActivity(v, intent, tag);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
        }
        return success;
    }


该段代码在 \packages\apps\Launcher2\src\com\android\launcher2\Launcher.java 界面中定义 , 该界面是 Launcher 应用的主界面 ;






二、 Launcher 中的 startActivity(View v, Intent intent, Object tag) 方法分析


1 . Launcher 中的启动方法 : Launcher 应用中启动 Android 应用 , 调用 startActivity(View v, Intent intent, Object tag) 方法 , 在该方法中 , 启动 Android 应用的启动 Activity ;



3 . 实际启动方法 : 在 startActivity(View v, Intent intent, Object tag) 方法中启动 Android 应用的核心方法是 startActivity(intent, opts.toBundle()) 和 startActivity(intent) 启动安卓应用界面 ;


( 该 startActivity(intent) 方法就是我们经常调用的启动界面的方法 )



4 . Intent 来源 : 该启动 的 Intent 参数是之前 onClick 方法中从 Launcher 中的图标组件中获取的 Tag 标签 ;


public void onClick(View v) {
  // 该从 View v 组件中获取的标签 Tag 就是 Intent
  Object tag = v.getTag();
    if (tag instanceof ShortcutInfo) {
      // 获取 Intent 对象 , 可以直接根据该对象启动应用 Activity 界面
    final Intent intent = ((ShortcutInfo) tag).intent;
  }
}



5 . Launcher 应用中 startActivity(View v, Intent intent, Object tag) 方法源码 :


 

boolean startActivity(View v, Intent intent, Object tag) {
      // 设置一个启动标志
      // 查找当前任务栈中是否有与该 Activity 亲和性相同的任务栈
      // 如果有将该任务栈移动到前台 , 至于是创建新 Activity 还是复用原来 Activity , 按照该 Activity 的启动模式进行操作
      // 如果没有亲和性相同任务栈 , 创建任务栈 , 移动到前台
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            // Only launch using the new animation if the shortcut has not opted out (this is a
            // private contract between launcher and may be ignored in the future).
            boolean useLaunchAnimation = (v != null) &&
                    !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
            UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
            LauncherApps launcherApps = (LauncherApps)
                    this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
            if (useLaunchAnimation) {
                ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
                        v.getMeasuredWidth(), v.getMeasuredHeight());
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                    // Could be launching some bookkeeping activity
                    // 根据 Intent 启动点击图标对应的 Activity 界面
                    startActivity(intent, opts.toBundle());
                } else {
                    launcherApps.startMainActivity(intent.getComponent(), user,
                            intent.getSourceBounds(),
                            opts.toBundle());
                }
            } else {
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                  // 真实启动应用的方法
                  // 根据 Intent 启动点击图标对应的 Activity 界面
                    startActivity(intent);
                } else {
                    launcherApps.startMainActivity(intent.getComponent(), user,
                            intent.getSourceBounds(), null);
                }
            }
            return true;
        } catch (SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Launcher does not have the permission to launch " + intent +
                    ". Make sure to create a MAIN intent-filter for the corresponding activity " +
                    "or use the exported attribute for this activity. "
                    + "tag="+ tag + " intent=" + intent, e);
        }
        return false;
    }



该段代码在 \packages\apps\Launcher2\src\com\android\launcher2\Launcher.java 界面中定义 , 该界面是 Launcher 应用的主界面 ;






三、 Android 应用进程分析


1 . 应用启动前置操作 : 调用 startActivity(Intent intent) 方法 , 通过进程间通信 , 启动另外的 Android 应用 , 首先会去查找该 Activity 对应的包名 , 为该应用分配内存空间 , 并加载新应用对应的 main 函数 , 通过 Zygote 进程 , 孵化出新进程 , 在新进程中有方法区 , 堆区 , 栈区 , 等内存分区 ;



2 . 创建新进程过程 : Launcher 应用与 Zygote 进程进行通信后 , 通知 Zygote 进程 fork 一个新的进程 , 该新进程中通过 System Server 执行 ActivityThread , 执行 ActivityThread 中的主函数 ;



该 ActivityThread 中的主函数 main 中 , 有一个 Looper 不停的在不停的轮询读取 MessageQueue 中的消息 , 用于接收指令执行应用相关操作 ;




3 . 创建进程依据 : 根据包名查找创建进程 ;



① 根据包名查找创建进程 : 这个 ActivityThread 是指定包名的应用的函数入口 , 不是一个随意的入口 , 需要根据该包名查找对应的进程是否已经存在 ;


② 进程不存在 : 如果这个进程不存在 , 需要重新 fork 进程 , 执行后续一系列操作 , 那么这次启动称为冷启动 ;


③ 进程存在 : 如果之前该包名对应的应用存在 , 不需要重新创建进程 , 进程可以直接复用 , 那么这次启动称为热启动 ;




4 . 从进程角度分析冷启动与热启动 :



① 冷启动 : 运行程序后 , 应用启动 , 会为该应用启动一个新进程 ; 这次启动是冷启动 ;


② 退出应用 进程保留 : 点击回退键 , 应用退出 , 此时该进程进入后台 , 不会马上被杀死 ;


③ 热启动 : 再次启动该应用时 , 就会重新启用之前的进程 , 这次启动就是热启动 ;



这也是安卓手机为什么越用越卡的原因 , 进程进入后台 , 没有及时杀死 ; 苹果手机进程进入后台 , 会放入一个与运行时不相关的内存中 ;


目录
相关文章
|
15天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
41 14
|
16天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
16天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
24 0
|
6月前
|
监控 Linux 应用服务中间件
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
137 13
|
5月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
5月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
192 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
4月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
|
5月前
|
存储 缓存 安全
【Linux】冯诺依曼体系结构与操作系统及其进程
【Linux】冯诺依曼体系结构与操作系统及其进程
175 1
|
5月前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
127 2
|
5月前
|
SQL 自然语言处理 网络协议
【Linux开发实战指南】基于TCP、进程数据结构与SQL数据库:构建在线云词典系统(含注册、登录、查询、历史记录管理功能及源码分享)
TCP(Transmission Control Protocol)连接是互联网上最常用的一种面向连接、可靠的、基于字节流的传输层通信协议。建立TCP连接需要经过著名的“三次握手”过程: 1. SYN(同步序列编号):客户端发送一个SYN包给服务器,并进入SYN_SEND状态,等待服务器确认。 2. SYN-ACK:服务器收到SYN包后,回应一个SYN-ACK(SYN+ACKnowledgment)包,告诉客户端其接收到了请求,并同意建立连接,此时服务器进入SYN_RECV状态。 3. ACK(确认字符):客户端收到服务器的SYN-ACK包后,发送一个ACK包给服务器,确认收到了服务器的确
199 1