launcher3布局加载流程1

Launcher在安卓中是桌面的意思,Launcher可以单独打包编译成APK,通过adb命令安装到手机上。

AndroidManifest.xml文件

在Application的标签下,有两个activity和一个provider,它们分别是:Launcher、SettingsActivity和LauncherProvider;

  <!--
        Main launcher activity. When extending only change the name, and keep all the
        attributes and intent filters the same
主要launcher活动。扩展时只更改名称,并保留所有 属性和意图过滤器
        -->
<activity
  android:name="com.android.launcher3.Launcher"
  android:launchMode="singleTask"
  android:clearTaskOnLaunch="true"
  android:stateNotNeeded="true"
  android:windowSoftInputMode="adjustPan"
  android:screenOrientation="unspecified"
  android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
  android:resizeableActivity="true"
  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"/>
    <category android:name="android.intent.category.LAUNCHER_APP" />
  </intent-filter>
</activity>
<!-- 设置活动。扩展时,保持意向过滤器存在 -->
  <activity
            android:name="com.android.launcher3.SettingsActivity"
            android:label="@string/settings_button_text"
            android:theme="@android:style/Theme.DeviceDefault.Settings"
            android:autoRemoveFromRecents="true">
            <intent-filter>
                <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
  <!--
        The settings provider contains Home's data, like the workspace favorites. The permissions
        should be changed to what is defined above. The authorities should also be changed to
        represent the package name.
        -->
 <provider
            android:name="com.android.launcher3.LauncherProvider"
            android:authorities="com.android.launcher3.settings"
            android:exported="true"
            android:writePermission="com.android.launcher3.permission.WRITE_SETTINGS"
            android:readPermission="com.android.launcher3.permission.READ_SETTINGS" />
  • Launcher手机桌面的程序
  • SettingsActivity桌面的设置页面
  • LauncherProvider存储页面的布局信息

桌面布局

image.png

  • DragLayer是根布局,用来处理子View的拖动布局;
  • Workspace是用来装载桌面上的其他所有布局;
  • SearchDropTargetBar是用来显示一处和卸载的控件;
  • CellLayout是用来显示应用和桌面小工具的,一个Workspace中可以显示多个CellLayout;
  • PageIndicator是用来指示当前为第几页的CellLayout;
  • Hotseat是常用应用显示控件。

在示意图中,Workspace是SearchDropTargetBar、CellLayout、PageIndicator和Hotseat的父控件,而在xml文件中,我们看到Workspace是一个单独控件;

<com.android.launcher3.CellLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:launcher="http://schemas.android.com/apk/res-auto"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:hapticFeedbackEnabled="false"
  launcher:containerType="workspace" />

从Workspace.java的insertNewWorkspaceScreen方法可知,加载的是CellLayout子view,在Workspace的代码中,只有insertNewWorkspaceScreen()这块代码中有调用addView()的方法,可以看到它添加的View便是newScreen,而它又是通过LayoutInflater加载的View,通过查看workspace_screen.xml可以知道,它就是一个CellLayout。

主入口Launcher

首先关注Launcher.java的onCreate方法:

@Override
protected void onCreate(Bundle savedInstanceState) {
    ......
    LauncherAppState app = LauncherAppState.getInstance(this);

 mOldConfig = new Configuration(getResources().getConfiguration());
    mModel = app.getModel();
    mRotationHelper = new RotationHelper(this);
    InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
    ......
}

LauncherAppState类水用来保存一些全局的、核心的对象。主要有整个Launcher的工作台workspace、LauncehrModel、Launcher的应用图标缓存机制IconCache,以及设备的配置信息InvariantDeviceProfile。
通过Configuration获取屏幕的配置,通过LauncherAppState获取到LauncherModel的实例对象以及InvariantDeviceProfile的实例对象,在InvariantDeviceProfile的getPredefinedDeviceProfiles中会去device_profiles配置文件中去适配对应的配置信息。

LauncherAppState里调用了LauncherModel的初始化方法 initialize,参数是Launcher。
launcherModel中有startLoader方法:

 private boolean startLoader(Callbacks[] newCallbacks) {
        // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
        ItemInstallQueue.INSTANCE.get(mApp.getContext())
                .pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING);
        synchronized (mLock) {
            // If there is already one running, tell it to stop.
            boolean wasRunning = stopLoader();
            boolean bindDirectly = mModelLoaded && !mIsLoaderTaskRunning;
            boolean bindAllCallbacks = wasRunning || !bindDirectly || newCallbacks.length == 0;
            final Callbacks[] callbacksList = bindAllCallbacks ? getCallbacks() : newCallbacks;

            if (callbacksList.length > 0) {
                // Clear any pending bind-runnables from the synchronized load process.
                for (Callbacks cb : callbacksList) {
                    MAIN_EXECUTOR.execute(cb::clearPendingBinds);
                }
                LoaderResults loaderResults = new LoaderResults(
                        mApp, mBgDataModel, mBgAllAppsList, callbacksList);
                if (bindDirectly) {
                    // Divide the set of loaded items into those that we are binding synchronously,
                    // and everything else that is to be bound normally (asynchronously).
                    loaderResults.bindWorkspace(bindAllCallbacks);
                    // For now, continue posting the binding of AllApps as there are other
                    // issues that arise from that.
                    loaderResults.bindAllApps();
                    loaderResults.bindDeepShortcuts();
                    loaderResults.bindWidgets();
                    return true;
                } else {
                    stopLoader();
                    mLoaderTask = new LoaderTask(
                            mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults);
                    // Always post the loader task, instead of running directly
                    // (even on same thread) so that we exit any nested synchronized blocks
                    MODEL_EXECUTOR.post(mLoaderTask);
                }
            }
        }
        return false;
    }

该方法中创建了LoaderTask用来加载数据,该类实现了Runnable接口,run方法中根据mStopped的状态进行一个判断,然后最先执行的是loadWorkspace方法,里面是对Workspace的一些加载,包括屏幕数、应用数据、widget组建信息;调用mResults.bindAllApps方法绑定所有app,mResults.bindWidgets绑定小部件等等的一些列绑定。
Launcher里面数据比较多,包括所有应用的图标和应用数据,所有应用的Widget数据,桌面已添加的用户数据等,随着Android大版本演进,还有DeepShortcuts等新的数据类型。如果按照常规的加载做法,等加载数据完成后再显示到View,耗时就太长了。为了优化体验,Launcher于是采用了分批加载、分批绑定的做法。
WorkSpace的加载流程:
image.png

如果我的文章对您有帮助,还请您多多支持我。支付宝帮忙扫一下吧
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pengkai火火火

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值