Android Launcher源碼研究(三) 載入app流程2

來源:互聯網
上載者:User

標籤:app   介面   android   launcher   源碼   

接上次的。

首先Launcher實現了LauncherModel.Callbacks介面,APP資訊資料載入成功後 ,回調介面把app資訊顯示到Launcher的 workspace介面上,這個過程代碼裡面稱為bind。

下面是個類調用過程的時序圖,不是很標準,不過能表達基本調用順序協助我們理解。





首先就是Launcher OnCreate中調用LauncherMode startLoader方法,這裡只看非同步方式 就是當前的頁面下標為-1,載入所有app資訊

mWorkspace.getCurrentPage()為-1的情況。
 mModel.startLoader(true, -1); 


 在LauncherMode類的startLoader方法裡面,我們需要執行個體化線程類 LoaderTask,大部分工作都在這裡面完成.

run方法的代碼:

            keep_running: {                // Elevate priority when Home launches for the first time to avoid                // starving at boot time. Staring at a blank home is not cool.                synchronized (mLock) {                    if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                            (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                    android.os.Process.setThreadPriority(mIsLaunching                            ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);                }                if (loadWorkspaceFirst) {                    if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                    loadAndBindWorkspace();                } else {                    if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps");                    loadAndBindAllApps();                }                if (mStopped) {                    break keep_running;                }                // Whew! Hard work done.  Slow us down, and wait until the UI thread has                // settled down.                synchronized (mLock) {                    if (mIsLaunching) {                        if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                    }                }                waitForIdle();                // second step                if (loadWorkspaceFirst) {                    if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                    loadAndBindAllApps();                } else {                    if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace");                    loadAndBindWorkspace();                }                // Restore the default thread priority after we are done loading items                synchronized (mLock) {                    android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);                }            }

我們定位到 loadAndBindWorkspace 方法 載入workspace介面


        private void loadAndBindWorkspace() {            mIsLoadingAndBindingWorkspace = true;            // Load the workspace            if (DEBUG_LOADERS) {                Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);            }            if (!mWorkspaceLoaded) { //第一次載入                loadWorkspace(); //載入                synchronized (LoaderTask.this) {                    if (mStopped) {                        return;                    }                    mWorkspaceLoaded = true;                }            }            // Bind the workspace            bindWorkspace(-1);//綁定資料到UI        }

</pre><p></p><p>loadWorkspace方法就是載入手機裡面的所有app資訊,包括app widget, folder 並且儲存到ArrayList中,後面顯示這些東西到UI上。</p><p>資料我們儲存好以後調用bindWorkspace(-1)開始顯示資料到workspace,裡麵包含了很多調用方法,主要是資料排序,清除以前綁定的UI資料。</p><p>在bindWorkspace方法裡面,調用了一些filter方法,這個地方主要是排序和過濾,分別判斷需要載入到那個螢幕裡面.</p><p></p><pre code_snippet_id="533506" snippet_file_name="blog_20141126_4_7063071" name="code" class="java">            r = new Runnable() {                public void run() {                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);                    if (callbacks != null) {                        callbacks.startBinding();//綁定之前,清理之前的資料,簡單就這麼理解                    }                }            };            runOnMainThread(r);//UI更新需要在主線程中

下面這個方法就是把資料添加到workspace的螢幕中去.

            bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                    currentFolders, null);

      private void bindWorkspaceItems(final Callbacks oldCallbacks,                final ArrayList<ItemInfo> workspaceItems,                final ArrayList<LauncherAppWidgetInfo> appWidgets,                final HashMap<Long, FolderInfo> folders,                ArrayList<Runnable> deferredBindRunnables) {            final boolean postOnMainThread = (deferredBindRunnables != null);            // Bind the workspace items            int N = workspaceItems.size();            for (int i = 0; i < N; i += ITEMS_CHUNK) {                final int start = i;                final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                final Runnable r = new Runnable() {                    @Override                    public void run() {                        Callbacks callbacks = tryGetCallbacks(oldCallbacks);                        if (callbacks != null) {                            callbacks.bindItems(workspaceItems, start, start+chunkSize);//顯示app資訊到UI上                        }                    }                };                if (postOnMainThread) {                    deferredBindRunnables.add(r);                } else {                    runOnMainThread(r);                }            }            // Bind the folders            if (!folders.isEmpty()) {                final Runnable r = new Runnable() {                    public void run() {                        Callbacks callbacks = tryGetCallbacks(oldCallbacks);                        if (callbacks != null) {                            callbacks.bindFolders(folders);//顯示folders                        }                    }                };                if (postOnMainThread) {                    deferredBindRunnables.add(r);                } else {                    runOnMainThread(r);                }            }            // Bind the widgets, one at a time            N = appWidgets.size();            for (int i = 0; i < N; i++) {                final LauncherAppWidgetInfo widget = appWidgets.get(i);                final Runnable r = new Runnable() {                    public void run() {                        Callbacks callbacks = tryGetCallbacks(oldCallbacks);                        if (callbacks != null) {                            callbacks.bindAppWidget(widget);//綁定AppWidget資訊                        }                    }                };                if (postOnMainThread) {                    deferredBindRunnables.add(r);                } else {                    runOnMainThread(r);                }            }        }



我們這裡只看第一個綁定shortcut資訊代碼,其他2個其實道理差不多.

    public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end) {        setLoadOnResume();        // Get the list of added shortcuts and intersect them with the set of shortcuts here        Set<String> newApps = new HashSet<String>();        newApps = mSharedPrefs.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, newApps);        Workspace workspace = mWorkspace;        for (int i = start; i < end; i++) {            final ItemInfo item = shortcuts.get(i);            // Short circuit if we are loading dock items for a configuration which has no dock            if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&                    mHotseat == null) {                continue;            }            switch (item.itemType) {                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                    ShortcutInfo info = (ShortcutInfo) item;                    String uri = info.intent.toUri(0).toString();                    View shortcut = createShortcut(info);                    workspace.addInScreen(shortcut, item.container, item.screen, item.cellX,                            item.cellY, 1, 1, false);                    boolean animateIconUp = false;                    synchronized (newApps) {                        if (newApps.contains(uri)) {                            animateIconUp = newApps.remove(uri);                        }                    }                    if (animateIconUp) {                        // Prepare the view to be animated up                        shortcut.setAlpha(0f);                        shortcut.setScaleX(0f);                        shortcut.setScaleY(0f);                        mNewShortcutAnimatePage = item.screen;                        if (!mNewShortcutAnimateViews.contains(shortcut)) {                            mNewShortcutAnimateViews.add(shortcut);                        }                    }                    break;                case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                    FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,                            (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),                            (FolderInfo) item, mIconCache);                    workspace.addInScreen(newFolder, item.container, item.screen, item.cellX,                            item.cellY, 1, 1, false);                    break;            }        }        workspace.requestLayout();    }

 

重點就是下面這個,把資料畫到UI上面,座標資訊,APP資訊.

                    workspace.addInScreen(shortcut, item.container, item.screen, item.cellX,                            item.cellY, 1, 1, false);


最後我們調用 finishBindingItems完成調用,這個方法裡面還包括了滑動和顯示APP動畫方法的處理。 

        if (mVisible || mWorkspaceLoading) {            Runnable newAppsRunnable = new Runnable() {                @Override                public void run() {                    runNewAppsAnimation(false);                }            };            boolean willSnapPage = mNewShortcutAnimatePage > -1 &&                    mNewShortcutAnimatePage != mWorkspace.getCurrentPage();            if (canRunNewAppsAnimation()) {                // If the user has not interacted recently, then either snap to the new page to show                // the new-apps animation or just run them if they are to appear on the current page                if (willSnapPage) {                    mWorkspace.snapToPage(mNewShortcutAnimatePage, newAppsRunnable);                } else {                    runNewAppsAnimation(false);                }            } else {                // If the user has interacted recently, then just add the items in place if they                // are on another page (or just normally if they are added to the current page)                runNewAppsAnimation(willSnapPage);            }        }

詳細的我們到後面繼續分析。還包括具體Workspace上面的介面格子cell是怎麼設計和APP添加位置的計算問題。


若有問題,請指出,謝謝~ O(∩_∩)O~





Android Launcher源碼研究(三) 載入app流程2

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.