Android Launcher源码研究(二) 加载app流程1

来源:互联网 发布:营销数据分析 pdf 编辑:程序博客网 时间:2024/06/01 09:56

今天主要分析Android Launcher源码中的一些重要类之间的关系,基本的加载流程。先来看一个类图



  Launcher.java 是主Activity 在onCreate方法里面初始化了LauncherMode实例.


LauncherApplication app = ((LauncherApplication)getApplication());

mModel = app.setLauncher(this);

直接进入LauncherApplication.java的方法 

    LauncherModel setLauncher(Launcher launcher) {        mModel.initialize(launcher);        return mModel;    }

这里的mModel就是LauncherModel类了,LauncherModel扮演者重要的角色,实际上是个广播,监控app的安装,改变,和卸载另外就是加载所有app信息

这里Launcher实现了Callbacks接口,直接加入到callbacks列表中,后面的很多功能都要靠它回调处理

    public void initialize(Callbacks callbacks) {        synchronized (mLock) {            mCallbacks = new WeakReference<Callbacks>(callbacks);        }    }


在Launcher.java  onCreate的代码中看下面的一段代码.

        if (!mRestoring) {            if (sPausedFromUserAction) {                // If the user leaves launcher, then we should just load items asynchronously when                // they return.                mModel.startLoader(true, -1);            } else {                // We only load the page synchronously if the user rotates (or triggers a                // configuration change) while launcher is in the foreground                mModel.startLoader(true, mWorkspace.getCurrentPage());            }        }

源码中注释也显示了2中情况,一种是当前用户的界面不是桌面可能是某个应用程序界面 这样我们通过后台异步加载。

另外一种情况是 刷新当前页面的app信息数据. 

现在定位到LauncherMode.java源码中startLoader方法 部分代码如下.

                if (synchronousBindPage > -1 && mAllAppsLoaded && mWorkspaceLoaded) {                    mLoaderTask.runBindSynchronousPage(synchronousBindPage);//同步加载当前页                } else {                    sWorkerThread.setPriority(Thread.NORM_PRIORITY);                    sWorker.post(mLoaderTask);//异步加载                }
和上面讲的一样,加载当前页面信息还是更新所有信息. synchronousBindPage就是当前用户滑动到第几个屏幕,一共是5个屏幕.

我们用到了LoaderTask这个类是一个Runnable实现.  这个地方用的是HandlerThread (这个类我以前没用过,一直是自己获取Looper再处理的 )

这个类就是具体载入appinfo,appwidget,  folder的信息了。

我们看看LoaderTask run方法实现. 注意 LoaderTask 是LauncherMode的内部类.  

            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);                }            }

按照源码的注释 是第一次加载workspace , 第二次加载所有的app 信息,你会发现 loadAndBindAllApps方法和loadAndBindWorkspace 2次调用是倒着的。

我的理解就是  先执行加载workspace 再执行加载all apps.

我们定位到 loadAndBindWorkspace方法中,


   if (!mWorkspaceLoaded) {                loadWorkspace();                synchronized (LoaderTask.this) {                    if (mStopped) {                        return;                    }                    mWorkspaceLoaded = true;                }            }

如果workspace还没加载就调用loadWorkspace方法. 定位到这个方法里面,一目了然发现 都是直接获取应用程序信息了包括widget.

直接调用了 PackageManager,AppWidgetManager,ContentResolver 获取信息.

读取信息保存后 我们需要与workspace汇合,这个地方是调用bindWorkspace

在这个方面里面我们会发现使用前面说的callbacks进行回调完整数据与View的绑定显示.

      /**         * Binds all loaded data to actual views on the main thread.         */        private void bindWorkspace(int synchronizeBindPage) {            final long t = SystemClock.uptimeMillis();            Runnable r;            // Don't use these two variables in any of the callback runnables.            // Otherwise we hold a reference to them.            final Callbacks oldCallbacks = mCallbacks.get();            if (oldCallbacks == null) {                // This launcher has exited and nobody bothered to tell us.  Just bail.                Log.w(TAG, "LoaderTask running with no launcher");                return;            }            final boolean isLoadingSynchronously = (synchronizeBindPage > -1);            final int currentScreen = isLoadingSynchronously ? synchronizeBindPage :                oldCallbacks.getCurrentWorkspaceScreen();            // Load all the items that are on the current page first (and in the process, unbind            // all the existing workspace items before we call startBinding() below.            unbindWorkspaceItemsOnMainThread();            ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();            ArrayList<LauncherAppWidgetInfo> appWidgets =                    new ArrayList<LauncherAppWidgetInfo>();            HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();            HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();            synchronized (sBgLock) {                workspaceItems.addAll(sBgWorkspaceItems);                appWidgets.addAll(sBgAppWidgets);                folders.putAll(sBgFolders);                itemsIdMap.putAll(sBgItemsIdMap);            }            ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();            ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();            ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                    new ArrayList<LauncherAppWidgetInfo>();            ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                    new ArrayList<LauncherAppWidgetInfo>();            HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();            HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();            // Separate the items that are on the current screen, and all the other remaining items            filterCurrentWorkspaceItems(currentScreen, workspaceItems, currentWorkspaceItems,                    otherWorkspaceItems);            filterCurrentAppWidgets(currentScreen, appWidgets, currentAppWidgets,                    otherAppWidgets);            filterCurrentFolders(currentScreen, itemsIdMap, folders, currentFolders,                    otherFolders);            sortWorkspaceItemsSpatially(currentWorkspaceItems);            sortWorkspaceItemsSpatially(otherWorkspaceItems);            // Tell the workspace that we're about to start binding items            r = new Runnable() {                public void run() {                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);                    if (callbacks != null) {                        callbacks.startBinding();                    }                }            };            runOnMainThread(r);            // Load items on the current page            bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                    currentFolders, null);            if (isLoadingSynchronously) {                r = new Runnable() {                    public void run() {                        Callbacks callbacks = tryGetCallbacks(oldCallbacks);                        if (callbacks != null) {                            callbacks.onPageBoundSynchronously(currentScreen);                        }                    }                };                runOnMainThread(r);            }            // Load all the remaining pages (if we are loading synchronously, we want to defer this            // work until after the first render)            mDeferredBindRunnables.clear();            bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,                    (isLoadingSynchronously ? mDeferredBindRunnables : null));            // Tell the workspace that we're done binding items            r = new Runnable() {                public void run() {                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);                    if (callbacks != null) {                        callbacks.finishBindingItems();                    }                    // If we're profiling, ensure this is the last thing in the queue.                    if (DEBUG_LOADERS) {                        Log.d(TAG, "bound workspace in "                            + (SystemClock.uptimeMillis()-t) + "ms");                    }                    mIsLoadingAndBindingWorkspace = false;                }            };            if (isLoadingSynchronously) {                mDeferredBindRunnables.add(r);            } else {                runOnMainThread(r);            }        }


这段代码有很多需要解释的,本质就是app,widgets, folders获取并传给主界面。今天就分析到这里。后面还有很多,这次就分析到这里,


如有问题 ,欢迎指出 谢谢。O(∩_∩)O~


 

1 0
原创粉丝点击