墨香帶你學(xué)Launcher之(三)-綁定屏幕折柠、圖標(biāo)宾娜、文件夾和Widget

上一章我們講了Launcher的數(shù)據(jù)加載,包括:默認(rèn)配置應(yīng)用液走、文件夾以及widget的加載碳默,所有應(yīng)用的加載以及所有Widget的加載,數(shù)據(jù)加載完成后開始分批進(jìn)行繪制到桌面上缘眶,包含默認(rèn)配置bind嘱根,所有應(yīng)用bind,所有小部件bind巷懈。下面我就從這幾個方面進(jìn)行分析该抒,看看他們的加載過程。

1.默認(rèn)配置圖標(biāo)顶燕、Widget凑保、文件夾的綁定(bind)


上一章講到默認(rèn)配置加載的位置:

 private void loadAndBindWorkspace() {
            
            ...
            
            if (!mWorkspaceLoaded) {
                loadWorkspace();
                ...
            }

            // Bind the workspace
            bindWorkspace(-1);
        }

這里主要是加載默認(rèn)配置,然后調(diào)用bindWorkspace進(jìn)行綁定涌攻,我們先看一下流程圖:

launcher01.png

整個流程看似東西很多欧引,其實(shí)就是準(zhǔn)備數(shù)據(jù),然后開始綁定恳谎,下面我們看bindWorkspace的主要代碼:

private void bindWorkspace(int synchronizeBindPage) {
              //準(zhǔn)備參數(shù)
            ...

            //開始綁定
            ...

            bindWorkspaceScreens(oldCallbacks, orderedScreenIds);

            // Load items on the current page
            bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,
                    currentFolders, null);
            ...
            
            bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,
                    (isLoadingSynchronously ? mDeferredBindRunnables : null));

              //結(jié)束綁定
            ...
          
        }

我們先分析第一個方法:bindWorkspaceScreens芝此,我們知道桌面上的圖標(biāo)憋肖、文件夾等是放置到CellLayout(實(shí)際內(nèi)部還有一個容器)中的,因此我們要首先添加CellLayout整個容器婚苹,
也就是這個方法岸更,代碼:

private void bindWorkspaceScreens(final Callbacks oldCallbacks,
                                          final ArrayList<Long> orderedScreens) {
            final Runnable r = new Runnable() {
                @Override
                public void run() {
                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                    if (callbacks != null) {
                        callbacks.bindScreens(orderedScreens);
                    }
                }
            };
            runOnMainThread(r);
        }

代碼很簡單,就是調(diào)用回調(diào)函數(shù)callbacks.bindScreens膊升,這個回調(diào)函數(shù)是在Launcher中實(shí)現(xiàn)的怎炊,因此我們看流程圖:

launcher02.png

代碼實(shí)現(xiàn)就是在bindAddScreens方法中通過for循環(huán)添加CellLayout,比較簡單不再貼代碼廓译。

我們接著看第二第三個函數(shù)评肆,這兩個函數(shù)是一樣的,但是參數(shù)不一樣责循,從參數(shù)名字可以看到第一個bind當(dāng)前頁面的圖標(biāo)糟港、文件夾、widget的院仿,第二個是bind其他屏幕圖標(biāo)秸抚、文件夾、widget的歹垫,因此我們只講一個流程剥汤,剩下的是一樣的。

我們先看流程圖:

launcher03.png

從流程圖看其實(shí)就是三個for循環(huán)排惨,分別綁定圖標(biāo)吭敢、文件夾、小部件暮芭,

public void bindItems(final ArrayList<ItemInfo> shortcuts, final int start, final int end,
                          final boolean forceAnimateIcons) {
        ...
        
        for (int i = start; i < end; i++) {
            final ItemInfo item = shortcuts.get(i);

            // 如果是在Hotseat中并且沒有Hotseat則跳過繼續(xù)
            if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
                    mHotseat == null) {
                continue;
            }

            final View view;
            switch (item.itemType) {
                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                    ShortcutInfo info = (ShortcutInfo) item;
                    view = createShortcut(info);
                    break;
                case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                    view = FolderIcon.fromXml(R.layout.folder_icon, this,
                            (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
                            (FolderInfo) item, mIconCache);
                    break;
                default:
                    throw new RuntimeException("Invalid Item Type");
            }

            workspace.addInScreenFromBind(view, item.container, item.screenId, item.cellX,
                    item.cellY, 1, 1);
}

在上面的switch語句中判斷Item的類型鹿驼,根據(jù)不同類型來生成不同的View,最后通過workspace.addInScreenFromBind方法將view綁定到桌面上,我們接著看一下addInScreenFromBind這個方法辕宏,這個方法最后調(diào)用到Workspace中的addInScreen方法畜晰,在這個方法中有兩個參數(shù)spanX、spanY沒有講過瑞筐,我來解釋一下凄鼻,我們第一章講了圖標(biāo)排列到桌面上是按照4x4后者4x5等形式,那么每個單元是一個圖標(biāo)位置聚假,但是块蚌,小部件的占用不只是一個圖標(biāo),有可能幾個圖標(biāo)的位置膘格,而spanX就是橫向占用的單元格個數(shù)峭范,相應(yīng)的spanY就是Y方向的占用個數(shù)。根據(jù)控件的起始位置瘪贱,以及占用單元格個數(shù)就可以確定他在桌面上的位置虎敦。addInScreen代碼我就不貼了游岳,我只是在這說一下過程,進(jìn)入這個方法其徙,首先判斷container的類型,也就是父容器的類型:CellLayout還是Hotseat喷户,然后判斷是文件夾還是圖標(biāo)唾那,最后通過調(diào)用layout.addViewToCellLayout方法根據(jù)相應(yīng)的參數(shù)來添加到相應(yīng)的容器里面。

其他兩個的綁定也是差不多的褪尝,只是widget的相對復(fù)雜一點(diǎn)闹获,這里不再講解,后面我會單獨(dú)寫一章來講解widget的加載添加河哑。

2.所有應(yīng)用綁定(bind)


綁定所有應(yīng)用其實(shí)是綁定二級界面的所有應(yīng)用圖標(biāo)避诽,代碼開始位置是:LauncherModel中的loadAllApps方法,首先加載手機(jī)里的所有應(yīng)用信息璃谨,然后生成對應(yīng)的對象沙庐,最后通過調(diào)用callbacks.bindAllApplications方法將所有應(yīng)用綁定到二級界面,回調(diào)函數(shù)依然是在Launcher中實(shí)現(xiàn)佳吞,二級界面是AllAppsContainerView拱雏,根據(jù)代碼流程調(diào)用onAppsUpdated方法,在這個方法中排序最后調(diào)用updateAdapterItems方法底扳,這個界面是一個RecyclerView铸抑,準(zhǔn)備好數(shù)據(jù)庫,刷新適配器即可衷模。

3.所有Widget的綁定(bind)


綁定Widget也是從loadAllApps這個方法開始的鹊汛,在這個方法的最后面有個loadAndBindWidgetsAndShortcuts,通過這個方法綁定快捷方式和widget到小部件界面阱冶,看代碼:

public void loadAndBindWidgetsAndShortcuts(final Callbacks callbacks, final boolean refresh) {

        runOnWorkerThread(new Runnable() {
            @Override
            public void run() {
                updateWidgetsModel(refresh);
                final WidgetsModel model = mBgWidgetsModel.clone();

                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        Callbacks cb = getCallback();
                        if (callbacks == cb && cb != null) {
                            callbacks.bindAllPackages(model);
                        }
                    }
                });
                // update the Widget entries inside DB on the worker thread.
                LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(
                        model.getRawList());
            }
        });
    }

首先調(diào)用updateWidgetsModel方法刁憋,

void updateWidgetsModel(boolean refresh) {
        PackageManager packageManager = mApp.getContext().getPackageManager();
        final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
        widgetsAndShortcuts.addAll(getWidgetProviders(mApp.getContext(), refresh));
        Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
        widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));
        mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);
    }

在這個方法中首先調(diào)用getWidgetProviders方法來加載所有的小部件信息,然后通過packageManager.queryIntentActivities方法加載所有的快捷方式信息熙揍,最后將所有的信息放置到WidgetsModel中职祷,完成后通過調(diào)用callbacks.bindAllPackages回調(diào)函數(shù)開始綁定所有的小部件和快捷方式,回調(diào)函數(shù)在Launcher中實(shí)現(xiàn)届囚,然后調(diào)用WidgetsContainerView中的addWidgets方法傳入WidgetsModel對象有梆,然后通過調(diào)用刷新適配器來刷新小部件界面。

最后:這一章相對簡單意系,主要是UI的繪制泥耀,有一些流程我沒有講,主要是UI繪制其實(shí)和自定義view相關(guān)蛔添,很多人一看就會了痰催,所以不再講解兜辞,不會的可以去看看源碼。

Github地址:Launcher3_mx

首發(fā)地址:墨香博客

微信公眾賬號:Code-MX

注:本文原創(chuàng)夸溶,轉(zhuǎn)載請注明出處逸吵,多謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缝裁,一起剝皮案震驚了整個濱河市扫皱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捷绑,老刑警劉巖韩脑,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異粹污,居然都是意外死亡段多,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門壮吩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來进苍,“玉大人,你說我怎么就攤上這事粥航±拍螅” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵递雀,是天一觀的道長柄延。 經(jīng)常有香客問我,道長缀程,這世上最難降的妖魔是什么搜吧? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮杨凑,結(jié)果婚禮上滤奈,老公的妹妹穿的比我還像新娘。我一直安慰自己撩满,他們只是感情好蜒程,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伺帘,像睡著了一般昭躺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伪嫁,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天领炫,我揣著相機(jī)與錄音,去河邊找鬼张咳。 笑死帝洪,一個胖子當(dāng)著我的面吹牛似舵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播葱峡,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼砚哗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了族沃?” 一聲冷哼從身側(cè)響起频祝,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脆淹,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沽一,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盖溺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铣缠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烘嘱。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蝗蛙,靈堂內(nèi)的尸體忽然破棺而出蝇庭,到底是詐尸還是另有隱情,我是刑警寧澤捡硅,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布哮内,位于F島的核電站,受9級特大地震影響壮韭,放射性物質(zhì)發(fā)生泄漏北发。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一喷屋、第九天 我趴在偏房一處隱蔽的房頂上張望琳拨。 院中可真熱鬧,春花似錦屯曹、人聲如沸狱庇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽密任。三九已至,卻和暖如春驳棱,著一層夾襖步出監(jiān)牢的瞬間批什,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工社搅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驻债,地道東北人乳规。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像合呐,于是被迫代替她去往敵國和親暮的。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容