文章目录

  • 一、 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 就是 IntentObject 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 . 从进程角度分析冷启动与热启动 :


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

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

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


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

更多相关文章

  1. 参考:修改android开机界面
  2. Android中String资源文件的String.format方法(java)
  3. 在Ubuntu中和Android中添加开机自启动的守护进程
  4. android 程序启动界面的短暂黑屏解决办法
  5. android工程建立到最后一步提示unsupported template dependency
  6. android进程间共享简单数据
  7. 自己封装的Android sqlite-helper.jar包使用方法
  8. Android四种点击事件方法
  9. Android使用Parcelable传递对象方法及注意事项

随机推荐

  1. Android(安卓)最新面试题
  2. Android studio 解析网页数据,把网页Json
  3. 【Android】安卓AVD无法上网解决方案
  4. Android(安卓)Camera API2中采用CameraMe
  5. Android(安卓)Studio 完美修改应用包名
  6. Android 给textview添加下划线的一种方法
  7. android事件拦截处理机制图解
  8. android logcat鼠标悬浮提示过快
  9. android中intent传递数据的方式
  10. android check symbols in so