【Android 性能优化】应用启动优化 ( 安卓应用启动分析 | ActivityThread 主函数分析 | 应用初始化 | 启动优化项目 )

2023-03-27 21:40:23 浏览数 (1)

文章目录

  • 一、 应用入口函数 ActivityThread 主函数 main
  • 二、 ActivityThread 类 attach 方法 ( 应用加载 )
  • 三、 ActivityThread 类 handleBindApplication 方法 ( 应用创建 )
  • 四、 启动优化项目

一、 应用入口函数 ActivityThread 主函数 main


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

2 . Android 应用主函数简介 : 安卓应用的 main 函数定义在 ActivityThread.java 中 , 该主函数被封装起来了 , Android 应用在编译之后 , 是需要被打包到 apk 安装文件中的 , 这是整个应用的入口函数 , 这个入口文件就是 ActivityThread.java 类 ;

  • 安卓应用主函数 : Android 开发者开发安卓应用时 , 是不需要自己定义主函数的 , 由开发环境自动生成 ;
  • 苹果应用主函数 : iOS 开发者开发苹果应用程序时 , 需要自己写主函数 ;

3 . Java 栈内操作 : 在 Java 栈区域 , 会实例化 Application , 调用 Application 的 onCreate 方法 , 然后开启主界面 Activity ; 这些操作都是在 ActivityThread 中完成的 ;

4 . 应用入口主函数部分代码示例 : 下面代码是 ActivityThread 部分代码 , 省略

1

万行代码 , 只展示下主函数 ;

代码语言:javascript复制
public final class ActivityThread {
    public static void main(String[] args) {
    	// 主函数中先初始化 Looper MessageQueue 
    	// 将主线程转为 Looper 线程 
    	// 这也是在 Activity 中可以直接定义 Handler 就可以使用的原因 
        Looper.prepareMainLooper();

		// 这是主线程 
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

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

该代码路径为 frameworksbasecorejavaandroidappActivityThread.java , 这是 Android 应用的入口主函数定义文件

二、 ActivityThread 类 attach 方法 ( 应用加载 )


1 . attach 方法引入 : 在上述 ActivityThread 类中的 main 函数中 , 创建 ActivityThread 对象 , 并调用了该对象的 attach 方法 , 下面开始分析该方法的源码 ;

代码语言:javascript复制
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

在 attach 方法中 , 开启应用 , 加载 application 应用 , 然后加载 Activity 界面 ;

2 . 加载 Application 应用过程 :

① 获取进程引用 : 首先获取进程引用 IActivityManager mgr , 此处涉及进程通信 , IActivityManager 是进程的引用 , 可以与其它进程进行通信 ;

代码语言:javascript复制
// ActivityThread.java
final IActivityManager mgr = ActivityManagerNative.getDefault();

② 绑定 Application 应用 : 调用 IActivityManager 对象的 attachApplication 方法 , 调用该方法后 , 通过跨进程通信方式回调 ActivityThread 中的 handleBindApplication 方法 , 这个操作是由系统回调的 , 主要操作是初始化应用 Application ;

代码语言:javascript复制
// ActivityThread.java
mgr.attachApplication(mAppThread);

3 . ActivityThread.java 中的 attach 方法代码 : 展示部分代码细节 , 详细的类 , 去查看 ActivityThread.java 源码 ;

代码语言:javascript复制
	// ActivityThread.java
    private void attach(boolean system) {
    
			// mgr 是进程 , 涉及到进程间通信 , IActivityManager 是进程的引用
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
             	// 绑定 Application 应用
             	// 调用该方法后 , 通过进程方式回调 ActivityThread 中的 handleBindApplication 方法
             	// 这个操作是由系统回调的 
             	// 主要操作是初始化应用 Application
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
            
    }

该代码路径为 frameworksbasecorejavaandroidappActivityThread.java , 这是 Android 应用的入口主函数定义文件

三、 ActivityThread 类 handleBindApplication 方法 ( 应用创建 )


handleBindApplication 处理 Application 应用绑定方法 , 这是创建 Application 应用核心过程 ;

1 . 方法调用者 : 该方法是由进程回调的 , 回调时传入的 AppBindData data 参数 , 包含了所有应用相关信息 , 如创建位置 , 包名 ;

代码语言:javascript复制
// ActivityThread.java
private void handleBindApplication(AppBindData data) {
}

2 . 创建应用核心代码 : 从进程中传入的 AppBindData data 参数的 info 信息中获取 Application 应用 , 这是获取应用的核心方法 ;

( 此时该 Application 是一个空的应用 , 还没有执行 onCreate 方法 )

代码语言:javascript复制
// ActivityThread.java
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;

3 . 执行应用 Application 的 onCreate 方法 : 下面的代码会触发执行 Application 的 onCreate 方法 ;

代码语言:javascript复制
// ActivityThread.java
mInstrumentation.callApplicationOnCreate(app);

4 . Instrumentation 的 callApplicationOnCreate 方法 : 很简单的调用方法 , 直接调用 Application 的 onCreate 方法 ;

代码语言:javascript复制
	// Instrumentation.java
    public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }

该代码所在文件路径为 frameworksbasecorejavaandroidappInstrumentation.java

5 . ActivityThread 类 handleBindApplication 方法部分源码参考 :

代码语言:javascript复制
	// ActivityThread.java
    private void handleBindApplication(AppBindData data) {
        // ... 省略 1 万行代码

        // Allow disk access during application and provider setup. This could
        // block processing ordered broadcasts, but later processing would
        // probably end up doing the same disk access.
        // 允许磁盘在应用和 provider 创建时访问 . 
        // 该操作可能阻塞处理有序广播 , 但是稍后处理会完毕后 , 会允许同样的磁盘访问 ; 
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
        try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            // 进程中传入的 AppBindData data 参数 , 包含了 Application 应用
            // 这是创建 Application 的过程
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;

            try {
            	// 执行 Application 的 onCreate 方法
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to create application "   app.getClass().getName()
                          ": "   e.toString(), e);
                }
            }
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
    }

该代码路径为 frameworksbasecorejavaandroidappActivityThread.java , 这是 Android 应用的入口主函数定义文件

四、 启动优化项目

在 Launcher 应用点击图标后 , 启动应用 , 系统为应用开启进程 , 分配内存的步骤是无法干预的 , 开发者能做启动优化的地方只有两个位置 , 一个是 Application 的 onCreate 方法 , 另一个是 Activity 的 onCreate 方法 ;

1 . Application 的 onCreate 方法 : 在应用的 Application 创建时 , 需要调用 Application 中的 onCreate 方法 , 这里面绝对不能有耗时操作 , 直接影响到 ActivityThread 中初始化 Application 步骤的消耗时间 ;

2 . Activity 的 onCreate 方法 : 一般在 Activity 界面中 , 需要加载 xml 布局文件 , 显示布局文件中的画面 ;

0 人点赞