Android Launcher加载流程源码分析

本文详细分析了Android Launcher的启动过程,从ActivityManagerService.systemReady开始,探讨了startHomeActivityLocked、getHomeIntent、onCreate方法,以及LauncherAppState的初始化。接着,介绍了如何在后台线程通过LauncherModel加载应用、文件夹和小部件信息,并使用Handler在主线程中绑定到UI。文章涵盖了从数据库读取数据、填充不同集合以及如何将这些元素显示到桌面上的关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Launcher加载流程分析

最近开始接手Launcher模块,为了更好的技术积累,也看到很多大神在优快云上发的博文,就有了在优快云写博客的想法,这篇博文是我在研究了一段时间Launcher3后写的,可能有不对的,望大家拍砖。首先我们可以先参考这篇http://blog.youkuaiyun.com/yanbober/article/details/50525559博文,这篇博文介绍了launcher的代码主流程框架,这里我直接贴代码分析。

Launcher首次启动是通过ActivityManagerService.systemReady方法启动的,在Android系统启动中会启动system_server进程,在SystemServer.java中可以找到调用ActivityManagerService.systemReady的地方,来看一下ActivityManagerService中的systemReady方法

public void systemReady(final Runnable goingCallback) {
    ...//省略
    startHomeActivityLocked(currentUserId, "systemReady");
    ...
}

继续看startHomeActivityLocked()方法

boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            // We are running in factory test mode, but unable to find
            // the factory test app, so just sit around displaying the
            // error message and don't try to start anything.
            return false;
        }
        Intent intent = getHomeIntent();//这里得到Launcher的Intent
        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
            // Don't do this if the home app is currently being
            // instrumented.
            aInfo = new ActivityInfo(aInfo);
            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
            if (app == null || app.instrumentationClass == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                //这里就会启动
                mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
            }

            /// M: PerfService for recording the last pause activity information. @{
   
            if (mStackSupervisor.mLastResumedActivity.packageName == null ||
                    mStackSupervisor.isUpdatedLastActivityWhenStartHome(aInfo.packageName,
                            aInfo.name)) {
                mStackSupervisor.mLastResumedActivity.packageName = aInfo.packageName;
                mStackSupervisor.mLastResumedActivity.activityName = aInfo.name;
                mStackSupervisor.mLastResumedActivity.activityType =
                        ActivityRecord.HOME_ACTIVITY_TYPE;
            }
            /// @}
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }

        return true;
    }

来看下getHomeIntent()方法

Intent getHomeIntent() {
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);//CATEGORY_HOME
        }
        return intent;
    }

在Launcher3中的AndroidManifest.xml中有注册这个Category的activity

<activity
            android:name="com.android.launcher3.Launcher"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true"
            android:stateNotNeeded="true"
            android:theme="@style/Theme"
            android:configChanges="mcc|mnc"
            android:windowSoftInputMode="adjustPan"
            android:screenOrientation="portrait"
            android:resumeWhilePausing="true"
            android:taskAffinity=""
            android:enabled="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY"/>
            </intent-filter>
        </activity>

简单分析完了Launcher是怎么被启动的,现在就来看Launcher本身的启动和加载流程,现在来看Launcher.java的onCreate方法,我在一些地方加了注释

@Override
protected void onCreate(Bundle savedInstanceState) {
    /*这两行初始化LauncherAppState,这个单例对象,会注册应用安装、卸载、更新,配置变化等广播,同时会
    初始化LauncherModel,里面有一个内部类LoaderTask用来获取数据,初始化桌面*/
    LauncherAppState.setApplicationContext(getApplicationContext());
    LauncherAppState app = LauncherAppState.getInstance();
    /*new InvariantDeviceProfile对象,从名字看意思是不变的设备相关参数存储类,里面会初始化管理横
    竖屏的两个DeviceProfile对象*/
    app.RenewInvariantDeviceProfile();
    //获得横竖屏的DeviceProfile对象
    mDeviceProfile = getResources().getConfiguration().orientation
                == Configuration.ORIENTATION_LANDSCAPE ?
                        app.getInvariantDeviceProfile().landscapeProfile
                            : app.getInvariantDeviceProfile().portraitProfile;   
    mModel = app.setLauncher(this);//获取在LauncherAppState中new LauncherModel对象
    mIconCache = app.getIconCache();//桌面图标缓存类

    mDragController = new DragController(this);//拖拽控制类
    mInflater = getLayoutInflater();
    mStateTransitionAnimation = new LauncherStateTransitionAnimation(this);//动画管理类
    mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);//widget管理类

    mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
    mAppWidgetHost.startListening();
    setupViews();//初始化布局控件
    mDeviceProfile.layout(this);//根据设备配置调整布局
    //调用mModel.startLoader方法开始加载异步加载桌面的数据,如app,folder,widget等
    if (!mRestoring) {
            if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
                // If the user leaves launcher, then we should just load items asynchronously when
                // they return.
                mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
            } else {
                // We only load the page synchronously if the user rotates (or triggers a
                // configuration change) while launcher is in the foreground
                mModel.startLoader(mWorkspace.getRestorePage());
            }
     }
     //是否启动向导界面
     if (shouldShowIntroScreen()) {
            showIntroScreen();
        } else {
            showFirstRunActivity();
            showFirstRunClings();
     }  

以上就是Launcher.java中onCreate方法中的部分代码,以上很多地方都用到了LauncherAppState这个单例对象,现在主要看这个类的构造方法,这个构造方法会初始化很多关键对象

private LauncherAppState() {
        if (sContext == null) {
            throw new IllegalStateException("LauncherAppState inited before app context set");
        }

        Log.v(Launcher.TAG, "LauncherAppState inited");

        if (sCon
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值