Android Framework-Launcher-数据的加载

Launcher 在我个人看来是简单且又复杂的一个模块。 简单是只要认真看,基本能看通UI部分大体逻辑,稍微动手改一下,就能看到效果,成就感大大滴有。 复杂是和SystemUI之间强绑定,看起来让我这菜狗CPU嗡嗡的。

Launcher 继承StatefulActivity 实现Callbacks 涉及类如下

  • LauncherModel
  • LauncherAppState
  • LoaderTask
  • LoaderResults

进入LauncheronCreate 看一下

java 复制代码
//packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
protected void onCreate(Bundle savedInstanceState) {

LauncherAppState app = LauncherAppState.getInstance(this);
mModel = app.getModel();

if (!mModel.addCallbacksAndLoad(this)) {
    if (!internalStateHandled) {
        // If we are not binding synchronously, pause drawing until initial bind complete,
        // so that the system could continue to show the device loading prompt
        mOnInitialBindListener = Boolean.FALSE::booleanValue;
    }
}

}

LauncherAppState 采用单例模式 ,在双构造里面引入了老演员InvariantDeviceProfile。 到现在大家不用理解太多。反正知道LauncherAppState里面是嘛都有啊~。

java 复制代码
public LauncherAppState(Context context) {
    this(context, LauncherFiles.APP_ICONS_DB);
}

public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
    mContext = context;

//出来吧 神龙 详情看第一篇
    mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
    mIconProvider = new LauncherIconProvider(context);
    mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
            iconCacheFileName, mIconProvider);
            //出来吧我的model
    mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext),
            iconCacheFileName != null);
    mOnTerminateCallback.add(mIconCache::close);
}

LauncherModel

java 复制代码
LauncherModel(@NonNull final Context context, @NonNull final LauncherAppState app,
        @NonNull final IconCache iconCache, @NonNull final AppFilter appFilter,
        final boolean isPrimaryInstance) {
    mApp = app;
    mBgAllAppsList = new AllAppsList(iconCache, appFilter);
    mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel,
            isPrimaryInstance);
}

LoaderTask其中的mModelDelegate 是使用的 LauncherModel 传递过来的单例对象。

java 复制代码
public LoaderTask(LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel dataModel,
        ModelDelegate modelDelegate, LoaderResults results) {
    mApp = app;
    mBgAllAppsList = bgAllAppsList;
    mBgDataModel = dataModel;
    mModelDelegate = modelDelegate;
    mResults = results;

    mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
    mUserManager = mApp.getContext().getSystemService(UserManager.class);
    mUserCache = UserCache.INSTANCE.get(mApp.getContext());
    mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
    mIconCache = mApp.getIconCache();
}

我们直接进入mModel.addCallbacksAndLoad 这段代码。

java 复制代码
public boolean addCallbacksAndLoad(@NonNull final Callbacks callbacks) {
    synchronized (mLock) {
        addCallbacks(callbacks);
        return startLoader(new Callbacks[] { callbacks });

    }
}

private boolean startLoader(@NonNull final Callbacks[] newCallbacks) {

//省略部分代码
//调用新的执行之前会将老的停掉
                     stopLoader();
                mLoaderTask = new LoaderTask(
                        mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, loaderResults);
                MODEL_EXECUTOR.post(mLoaderTask);
                
                //省略部分代码
}

为了避免重复执行代码,先 LoaderTask 继承了Runnable, 所以直接看run 方法。 允许我可耻的删除部分代码,我们只需要知道在该run 方法里面执行了5步

  • loadWorkspace 加载workSpace 数据,更新。
  • loadAllApps 加载所有app,更新。
  • loadDeepShortcuts 快捷方式,就是长按出来的那个小列表,更新。
  • allWidgetsList 加载小组件,更新。
  • loadFolderNames 加载文件夹,更新。
java 复制代码
   public void run() {
        synchronized (this) {
           //做了判断 如果stop没停止就不能开始
            if (mStopped) {
                return;
            }
        }

     
        try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
            List<ShortcutInfo> allShortcuts = new ArrayList<>();
          
            try {
                loadWorkspace(allShortcuts, memoryLogger);
            } finally {
                Trace.endSection();
            }
           

          //绑定
            mResults.bindWorkspace(true /* incrementBindId */);
            logASplit(logger, "bindWorkspace");

          //完成workSpace
            mModelDelegate.workspaceLoadComplete();


         
            // second step
            
            List<LauncherActivityInfo> allActivityList;
            try {
               allActivityList = loadAllApps();
            } finally {
                Trace.endSection();
            }
             //
            mResults.bindAllApps();
            logASplit(logger, "bindAllApps");
             
          //更新icon
            updateHandler.updateIcons(allActivityList,
                    LauncherActivityCachingLogic.newInstance(mApp.getContext()),
                    mApp.getModel()::onPackageIconsUpdated);
        

       
    
            // third step
            List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
        
            verifyNotStopped();
            mResults.bindDeepShortcuts();
          
            updateHandler.updateIcons(allDeepShortcuts,
                    new ShortcutCachingLogic(), (pkgs, user) -> { });

            // Take a break
        

            // fourth step
            List<ComponentWithLabelAndIcon> allWidgetsList =
                    mBgDataModel.widgetsModel.update(mApp, null);
           
            mResults.bindWidgets();
          
           

            updateHandler.updateIcons(allWidgetsList,
                    new ComponentWithIconCachingLogic(mApp.getContext(), true),
                    mApp.getModel()::onWidgetLabelsUpdated);
           
            // fifth step
            loadFolderNames();

            verifyNotStopped();
            updateHandler.finish();
            logASplit(logger, "finish icon update");

            mModelDelegate.modelLoadComplete();
            transaction.commit();
          
        } 

注意在每个加载完成的时候都会调用一下对应的mResults.doxxxx(); 我很好奇bindAllApps 干了啥

java 复制代码
public void bindAllApps() {
    // shallow copy
    AppInfo[] apps = mBgAllAppsList.copyData();
    int flags = mBgAllAppsList.getFlags();
    executeCallbacksTask(c -> c.bindAllApplications(apps, flags), mUiExecutor);
}



protected void executeCallbacksTask(CallbackTask task, Executor executor) {
    executor.execute(() -> {
        if (mMyBindingId != mBgDataModel.lastBindId) {
            Log.d(TAG, "Too many consecutive reloads, skipping obsolete data-bind");
            return;
        }
        for (Callbacks cb : mCallbacksList) {
            task.execute(cb);
        }
    });
}

okok,我们从上面代码知道Launcheroncreart() 方法里面把this 传给了LaucherMode,然后传给了LoaderResult,给到了作为参数构建了LoaderTask。 所以这里其实会回调回LauncherbindAllApplications

java 复制代码
@TargetApi(Build.VERSION_CODES.S)
public void bindAllApplications(AppInfo[] apps, int flags) {
    mAppsView.getAppsStore().setApps(apps, flags);
    PopupContainerWithArrow.dismissInvalidPopup(this);
    if (Utilities.ATLEAST_S) {
        Trace.endAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
                DISPLAY_ALL_APPS_TRACE_COOKIE);
    }
}

同样bindWorkspace 回调 bindStringCache 方法,大家感兴趣可以看下其他方法。

相关推荐
雨白15 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk15 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING15 小时前
RN容器启动优化实践
android·react native
恋猫de小郭18 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker1 天前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 天前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe2 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos