Launcher中的workspace加载流程(Allapps及Weights相似)

在这里插入图片描述

一、AndroidMainifest文件

在Application的标签中有activity和provider分别是Launcher,settingsActivity和LauncherProvider
其中,Launcher是手机可以看到的桌面,Settings是桌面的设置页面,LauncherProvider是用来存储页面的布局信息的 。

二、桌面布局:

1、Launcher界面配置的文件:

该位置一般处于:

\Launcher\res\xml\default_workspace.xml

注意有可能存在partner app此时的设置需要在partner中设置

<appwidget
launcher:className="" //应用的类
launcher:packageName=""//应用的包名
launcher:screen=""当前处于哪一屏
launcher:x=""   //图标X位置,左上角是第0个
launcher:y=""  //图标Y位置,左上角是第0个
launhcer:spanX="" //在x方向所占的格数
launcher:spanY="" //在y方向所占的格数
>

2、Launcher.java的onCreate方法:

在该部分中,完成了对于Launcher的一些初始化的工作,建立了LaunhcerAppState对象和LauncherModel对象的初始化,以及其他信息的初始化。开启数据加载设置

在这里插入图片描述

对于状态进行判断,我们不需要进行任何的配置
在这里插入图片描述
对于事件进行绑定,如果没有绑定则进行事件的绑定
在这里插入图片描述

3、LauncherModel的startLoader方法

在该方法中主要实现了对于LoaderTask进行启动
LocalModel对象主要保存在数据库中,主要保存了各种布局信息的

  • 对于当前的数据进行判断是否有效,在此时以线程的方式进行实现
private boolean mModelLoaded;
public boolean isModelLoaded(){
synchronized(mLock){
return mModelLoaded&& mLoaderTask==null;
}
}
  • startLoader方法
    该方法是加载程序的启动,在启动过程中并对于数据进行尝试同步绑定,若能够进行绑定则可以返回true,在实现的过程中调用的是工作线程LoaderTask

    public boolean startLoader() {
    //启动队列在数据加载之前,
    
        ItemInstallQueue.INSTANCE.get(mApp.getContext())
                .pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING);
        synchronized (mLock) {//以单线程的方式执行

            final Callbacks[] callbacksList = getCallbacks();
            if (callbacksList.length > 0) {
            //在同步加载过程中对于所有挂起的绑定可运行项进行清除
  
                for (Callbacks cb : callbacksList) {
                    MAIN_EXECUTOR.execute(cb::clearPendingBinds);
                }

                //对于旧的运行项进行一个清除
                stopLoader();
                LoaderResults loaderResults = new LoaderResults(
                        mApp, mBgDataModel, mBgAllAppsList, callbacksList);
                if (mModelLoaded && !mIsLoaderTaskRunning) {
                //将同步项绑定于workspace、allapps、快捷方式、桌面小组件
       
                    loaderResults.bindWorkspace();
           
                    loaderResults.bindAllApps();
                    loaderResults.bindDeepShortcuts();
                    loaderResults.bindWidgets();
                    return true;
                } else {
                //正在工作 的不是空则无需绑定
                    startLoaderForResults(loaderResults);
                }
            }
        }
        return false;
    }
//当有加载任务正在运行时则进行其停止运行
    public boolean stopLoader() {
        synchronized (mLock) {
            LoaderTask oldTask = mLoaderTask;
            mLoaderTask = null;
            if (oldTask != null) {
                oldTask.stopLocked();
                return true;
            }
            return false;
        }
    }
//对于LocalderTask进行启动:
 public void startLoaderForResults(LoaderResults results) {
        synchronized (mLock) {
            stopLoader();
            mLoaderTask = new LoaderTask(
                    mApp, mBgAllAppsList, mBgDataModel, mModelDelegate, results);
                    //发布加载程序任务
            MODEL_EXECUTOR.post(mLoaderTask);
        }
    }

4、LocalTask中的run方法:

 public void run() {
        synchronized (this) {
			//加锁的方式进行判断当mStopped是true时快速跳过
            // Skip fast if we are already stopped.
            if (mStopped) {
                return;
            }
        }

        Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
        TimingLogger logger = new TimingLogger(TAG, "run");
        //进行分批加载
        try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
            List<ShortcutInfo> allShortcuts = new ArrayList<>();//定义一个所有的快捷方式队列
            //执行该方法是对于Workspace的一些加载包括屏幕数、应用数据、widget组建信息等
            loadWorkspace(allShortcuts);
            logASplit(logger, "loadWorkspace");

            // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
            // sanitizeData should not be invoked if the workspace is loaded from a db different
            // from the main db as defined in the invariant device profile.
            // (e.g. both grid preview and minimal device mode uses a different db)
            if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
                verifyNotStopped();
                sanitizeData();
                logASplit(logger, "sanitizeData");
            }
            //在该方法中对于mStopped又进行了一次判断,若是true就抛出异常
            verifyNotStopped();
            //进行绑定
            mResults.bindWorkspace();
            logASplit(logger, "bindWorkspace");

            mModelDelegate.workspaceLoadComplete();
            // Notify the installer packages of packages with active installs on the first screen.
            sendFirstScreenActiveInstallsBroadcast();
            logASplit(logger, "sendFirstScreenActiveInstallsBroadcast");

            // Take a break
            waitForIdle();
            logASplit(logger, "step 1 complete");
            verifyNotStopped();
          //加载所有的app
            // second step
            List<LauncherActivityInfo> allActivityList = loadAllApps();
            logASplit(logger, "loadAllApps");

            verifyNotStopped();
            mResults.bindAllApps();
            logASplit(logger, "bindAllApps");

            verifyNotStopped();
            IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
            setIgnorePackages(updateHandler);
            updateHandler.updateIcons(allActivityList,
                    LauncherActivityCachingLogic.newInstance(mApp.getContext()),
                    mApp.getModel()::onPackageIconsUpdated);
            logASplit(logger, "update icon cache");

            if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
                verifyNotStopped();
                logASplit(logger, "save shortcuts in icon cache");
                updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(),
                        mApp.getModel()::onPackageIconsUpdated);
            }

            // Take a break
            waitForIdle();
            logASplit(logger, "step 2 complete");
            verifyNotStopped();
            //加载所有的快捷方式

            // third step
            List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
            logASplit(logger, "loadDeepShortcuts");

            verifyNotStopped();
            mResults.bindDeepShortcuts();
            logASplit(logger, "bindDeepShortcuts");

            if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) {
                verifyNotStopped();
                logASplit(logger, "save deep shortcuts in icon cache");
                updateHandler.updateIcons(allDeepShortcuts,
                        new ShortcutCachingLogic(), (pkgs, user) -> { });
            }

            // Take a break
            waitForIdle();
            logASplit(logger, "step 3 complete");
            verifyNotStopped();
            //加载桌面小部件

            // fourth step
            List<ComponentWithLabelAndIcon> allWidgetsList =
                    mBgDataModel.widgetsModel.update(mApp, null);
            logASplit(logger, "load widgets");

            verifyNotStopped();
            mResults.bindWidgets();
            logASplit(logger, "bindWidgets");
            verifyNotStopped();

            updateHandler.updateIcons(allWidgetsList,
                    new ComponentWithIconCachingLogic(mApp.getContext(), true),
                    mApp.getModel()::onWidgetLabelsUpdated);
            logASplit(logger, "save widgets in icon cache");
            //对于图标进行更新

            // fifth step
            if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
                loadFolderNames();
            }

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

            mModelDelegate.modelLoadComplete();
            transaction.commit();
        } catch (CancellationException e) {
            // Loader stopped, ignore
            logASplit(logger, "Cancelled");
        } finally {
            logger.dumpToLog();
        }
        TraceHelper.INSTANCE.endSection(traceToken);
    }

在该部分中完成了所有应用的图标和应用数据、所有应用的Widget数据、桌面已经添加的用户数据,在该部分中完成了分批加载分批绑定的方法:
在这里插入图片描述

5、workspace的加载流程

5、1了解BgDataModel.java

在这个方法中调可以看到所有应用图标对应的ItemInfo,所有AppWidgets数据对应的内容

 private static final String TAG = "BgDataModel";

    /**
     * Map of all the ItemInfos (shortcuts, folders, and widgets) created by
     * LauncherModel to their ids
     */
    public final IntSparseArrayMap<ItemInfo> itemsIdMap = new IntSparseArrayMap<>();

    /**
     * List of all the folders and shortcuts directly on the home screen (no widgets
     * or shortcuts within folders).
     */
    public final ArrayList<ItemInfo> workspaceItems = new ArrayList<>();

    /**
     * All LauncherAppWidgetInfo created by LauncherModel.
     */
    public final ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();

    /**
     * Map of id to FolderInfos of all the folders created by LauncherModel
     */
    public final IntSparseArrayMap<FolderInfo> folders = new IntSparseArrayMap<>();

    /**
     * Extra container based items
     */
    public final IntSparseArrayMap<FixedContainerItems> extraItems = new IntSparseArrayMap<>();

    /**
     * Maps all launcher activities to counts of their shortcuts.
     */
    public final HashMap<ComponentKey, Integer> deepShortcutMap = new HashMap<>();

    /**
     * Entire list of widgets.
     */
    public final WidgetsModel widgetsModel = new WidgetsModel();

    
    public int lastBindId = 0;

   

5、2loadWorkspace的分析

在该模块中主要完成了加载默认配置xml文件中的items,并把默认数据写入到数据库2、加载数据库的数据到缓存中
①:先进行数据库的清理重置:

 if (clearDb) {
            Log.d(TAG, "loadWorkspace: resetting launcher database");
            LauncherSettings.Settings.call(contentResolver,
                    LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
        }

在调用后跳转到LauncherProvider的loadDefaultFavoritesNecessary(),在该方法中判断是在deafultxml还是从数据库中读取数据,之后通过DatabaseHelper中的loadFavorites方法进行处理

case LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB: {
                mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
                return null;
            }
 @Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
            // TODO: Use multiple loaders with fall-back and transaction.
            int count = loader.loadLayout(db, new IntArray());

            // Ensure that the max ids are initialized
            mMaxItemId = initializeMaxItemId(db);
            mMaxScreenId = initializeMaxScreenId(db);
            return count;
        }

loadDefaultFavoritesNecessary()方法:若数据库木创建则加载默认的配置

synchronized private void loadDefaultFavoritesIfNecessary() {
        SharedPreferences sp = Utilities.getPrefs(getContext());
         //判断数据库是否创建
        if (sp.getBoolean(mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)) {
            Log.d(TAG, "loading default workspace");

            AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost();
            AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost);
            if (loader == null) {
                loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper);
            }
            if (loader == null) {
                final Partner partner = Partner.get(getContext().getPackageManager());
                if (partner != null && partner.hasDefaultLayout()) {
                    final Resources partnerRes = partner.getResources();
                    int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT,
                            "xml", partner.getPackageName());
                    if (workspaceResId != 0) {
                        loader = new DefaultLayoutParser(getContext(), widgetHost,
                                mOpenHelper, partnerRes, workspaceResId);
                    }
                }
            }

            final boolean usingExternallyProvidedLayout = loader != null;
            if (loader == null) {
                loader = getDefaultLayoutParser(widgetHost);
            }

            // There might be some partially restored DB items, due to buggy restore logic in
            // previous versions of launcher.
            mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
            // Populate favorites table with initial favorites
            if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0)
                    && usingExternallyProvidedLayout) {
                // Unable to load external layout. Cleanup and load the internal layout.
                mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
                mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
                        getDefaultLayoutParser(widgetHost));
            }
			//用于清理冗余数据
            clearFlagEmptyDbCreated();
        }
    }

实现步骤如下:
1、加载默认项的值
2、初始化数据信息并且将重置数据库信息
3、通过LauncherSettings.Favorites.CONTENT_URI查询Favorites表中的数据,
4、便利cursor进行数据整理。区分是应用、widget或是文件夹
5、读取完数据库后将需要更新和移除的item进行移除和更新

5、3数据绑定bindWorkspace():

根据获取的值将screenID将items分成了当前screen和其他screen,并进行排序
通过startBing方法进行一些清理工作,该方法无语Launcher.java中

public void startBinding() {
        Object traceToken = TraceHelper.INSTANCE.beginSection("startBinding");
        // Floating panels (except the full widget sheet) are associated with individual icons. If
        // we are starting a fresh bind, close all such panels as all the icons are about
        // to go away.
        AbstractFloatingView.closeOpenViews(this, true, TYPE_ALL & ~TYPE_REBIND_SAFE);

        setWorkspaceLoading(true);

        // Clear the workspace because it's going to be rebound
        mDragController.cancelDrag();

        mWorkspace.clearDropTargets();
        mWorkspace.removeAllWorkspaceScreens();
        mAppWidgetHost.clearViews();

        if (mHotseat != null) {
            mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout());
        }
        TraceHelper.INSTANCE.endSection(traceToken);
    }
  • 通过bindWorkspaceScreens(oldCallbacks, orderedScreenIds);绑定workspace screen,Callback对象处于BgDataModel中
  • 在Launcher,java中实现bindScreens和bindAddScreens方法
 @Override
    public void bindScreens(IntArray orderedScreenIds) {
        // Make sure the first screen is always at the start.
        if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
                orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != 0) {
            orderedScreenIds.removeValue(Workspace.FIRST_SCREEN_ID);
            orderedScreenIds.add(0, Workspace.FIRST_SCREEN_ID);
        } else if (!FeatureFlags.QSB_ON_FIRST_SCREEN && orderedScreenIds.isEmpty()) {
            // If there are no screens, we need to have an empty screen
            mWorkspace.addExtraEmptyScreen();
        }
        bindAddScreens(orderedScreenIds);

        // After we have added all the screens, if the wallpaper was locked to the default state,
        // then notify to indicate that it can be released and a proper wallpaper offset can be
        // computed before the next layout
        mWorkspace.unlockWallpaperFromDefaultPageOnNextLayout();
    }

    private void bindAddScreens(IntArray orderedScreenIds) {
        int count = orderedScreenIds.size();
        for (int i = 0; i < count; i++) {
            int screenId = orderedScreenIds.get(i);
            if (!FeatureFlags.QSB_ON_FIRST_SCREEN || screenId != Workspace.FIRST_SCREEN_ID) {
                // No need to bind the first screen, as its always bound.
                mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(screenId);
            }
        }
    }
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值