【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | Launcher 应用启用普通安卓应用 | 应用进程分析 )
上一篇博客 【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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
该段代码在 \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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
该段代码在 \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 . 从进程角度分析冷启动与热启动 :
① 冷启动 : 运行程序后 , 应用启动 , 会为该应用启动一个新进程 ; 这次启动是冷启动 ;
② 退出应用 进程保留 : 点击回退键 , 应用退出 , 此时该进程进入后台 , 不会马上被杀死 ;
③ 热启动 : 再次启动该应用时 , 就会重新启用之前的进程 , 这次启动就是热启动 ;
这也是安卓手机为什么越用越卡的原因 , 进程进入后台 , 没有及时杀死 ; 苹果手机进程进入后台 , 会放入一个与运行时不相关的内存中 ;
文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。
原文链接:hanshuliang.blog.csdn.net/article/details/106875970
- 点赞
- 收藏
- 关注作者
评论(0)