launcher4.0加载

来源:互联网 发布:淘宝二次认证不通过 编辑:程序博客网 时间:2024/05/17 03:47

摘自http://blog.csdn.net/chenshaoyang0011

Launcher在应用启动的时候,需要加载AppWidget,shortcut等内容项,通过调用LauncherModel.startLoader(),开始加载的工作。launcherModel中加载好的内容会通过

LauncherModel.Callbacks接口的回调函数将数据传给需要的组件,那先来看看Callbacks的定义:

[java] view plaincopyprint?
  1. public interface Callbacks {  
  2.         public boolean setLoadOnResume();  
  3.         public int getCurrentWorkspaceScreen();  
  4.         public void startBinding();  
  5.         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);  
  6.         public void bindFolders(HashMap<Long,FolderInfo> folders);  
  7.         public void finishBindingItems();  
  8.         public void bindAppWidget(LauncherAppWidgetInfo info);  
  9.         public void bindAllApplications(ArrayList<ApplicationInfo> apps);  
  10.         public void bindAppsAdded(ArrayList<ApplicationInfo> apps);  
  11.         public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);  
  12.         public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);  
  13.         public void bindPackagesUpdated();  
  14.         public boolean isAllAppsVisible();  
  15.         public void bindSearchablesChanged();  
  16.     }  
public interface Callbacks {        public boolean setLoadOnResume();        public int getCurrentWorkspaceScreen();        public void startBinding();        public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);        public void bindFolders(HashMap<Long,FolderInfo> folders);        public void finishBindingItems();        public void bindAppWidget(LauncherAppWidgetInfo info);        public void bindAllApplications(ArrayList<ApplicationInfo> apps);        public void bindAppsAdded(ArrayList<ApplicationInfo> apps);        public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);        public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);        public void bindPackagesUpdated();        public boolean isAllAppsVisible();        public void bindSearchablesChanged();    }

简单的了解下每个方法的用途:

 

setLoadOnResume()     由于Launcher继承自Activity,因此Launcher可能会处于paused状态(onPause()被调用),则有可能在这段时间内资源可能

发生了改变,如应用被删除或新应用安装,因此需要在onResume()中调用此方法进行重新加载。

getCurrentWorkspace()    获取当前屏幕的序号

startBinding()     通知Launcher加载开始,并更新Workspace上的shortcuts

bindItems(ArrayList<ItemInfo> shortcuts, int start, int end)     加载一批内容项到Workspace,加载的内容项包括,Application、shortcut、folder。

bindFolders(HashMap<Long, FolderInfo> folders)    加载folder的内容

finishBindingItems()    通知Launcher加载结束。

bindAppWidget(LauncherAppWidgetInfo item)    加载AppWidget到Workspace

bindAllApplications(final ArrayList<ApplicationInfo> apps)   在All Apps页加载所有应用的Icon

bindAppsAdded(ArrayList<ApplicationInfo> apps)   通知Launcher一个新的应用被安装,并加载这个应用

bindAppsUpdated(ArrayList<ApplicationInfo> apps)  通知Launcher一个应用发生了更新

bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent)    通知Launcher一个应用被删除了

bindPackagesUpdated()   通知Launcher多个应用发生了更新

isAllAppsVisible()用于在加载的过程中记录当前Launcher的状态,返回true则当前显示的All Apps

bindSearchablesChanged()当搜索/删除框状态发生改变时调用

了解了每个方法的作用之后,就可以开始进一步的分析了。

首先让我们回顾一下整个加载过程的流程是怎样的


通过在Launcher中调用LauncherModel.startLoader()方法,开始加载内容。

[java] view plaincopyprint?
  1. public void startLoader(Context context, boolean isLaunching) {  
  2.         synchronized (mLock) {  
  3.             ......  
  4.             // Don't bother to start the thread if we know it's not going to do anything  
  5.             if (mCallbacks != null && mCallbacks.get() != null) {  
  6.                 ......  
  7.                 mLoaderTask = new LoaderTask(context, isLaunching);  
  8.                 sWorkerThread.setPriority(Thread.NORM_PRIORITY);  
  9.                 sWorker.post(mLoaderTask);  
  10.             }  
  11.         }  
  12.     }  
public void startLoader(Context context, boolean isLaunching) {        synchronized (mLock) {            ......            // Don't bother to start the thread if we know it's not going to do anything            if (mCallbacks != null && mCallbacks.get() != null) {                ......                mLoaderTask = new LoaderTask(context, isLaunching);                sWorkerThread.setPriority(Thread.NORM_PRIORITY);                sWorker.post(mLoaderTask);            }        }    }

mLoaderTask是一个Runnable,被添加到消息队列之后,它的run() 方法会被调用。

[java] view plaincopyprint?
  1. public void run() {  
  2.             ......  
  3.             keep_running: {  
  4.                 ......  
  5.                 if (loadWorkspaceFirst) {  
  6.                     ......  
  7.                     loadAndBindWorkspace();  
  8.                 } else {  
  9.                     ......  
  10.                 }  
  11.   
  12.                 if (mStopped) {  
  13.                     break keep_running;  
  14.                 }  
  15.   
  16.                 ......  
  17.                 waitForIdle();  
  18.   
  19.                 // second step   
  20.                 if (loadWorkspaceFirst) {  
  21.                     ......  
  22.                     loadAndBindAllApps();  
  23.                 } else {  
  24.                     ......  
  25.                 }  
  26.                 ......  
  27.             }  
  28.             ......  
  29.         }  
public void run() {            ......            keep_running: {                ......                if (loadWorkspaceFirst) {                    ......                    loadAndBindWorkspace();                } else {                    ......                }                if (mStopped) {                    break keep_running;                }                ......                waitForIdle();                // second step                if (loadWorkspaceFirst) {                    ......                    loadAndBindAllApps();                } else {                    ......                }                ......            }            ......        }

加载的工作由两部分组成,第一部分是为Workspace加载内容第二部分则是为AllApps加载内容。每一部分的加载又可以分为两个步骤:1、由LauncherModel完成,主要

工作是从数据库中读取信息,并且按类别将内容项分装到不同的据结构中。2、由Launcher来完成,通过LauncherModel.Callbacks接口定义的回调方法,从LauncherModel

中获取的数据,将其显示到桌面

 

一、Workspace内容加载

run()中首先会调用loadAndBindWorkspace()方法开始Workspace的加载工作。

[java] view plaincopyprint?
  1. private void loadAndBindWorkspace() {  
  2.             ...  
  3.             if (!mWorkspaceLoaded) {  
  4.                 loadWorkspace();  
  5.                 synchronized (LoaderTask.this) {  
  6.                     if (mStopped) {  
  7.                         return;  
  8.                     }  
  9.                     mWorkspaceLoaded = true;  
  10.                 }  
  11.             }  
  12.   
  13.             // Bind the workspace   
  14.             bindWorkspace();  
  15.         }  
private void loadAndBindWorkspace() {            ...            if (!mWorkspaceLoaded) {                loadWorkspace();                synchronized (LoaderTask.this) {                    if (mStopped) {                        return;                    }                    mWorkspaceLoaded = true;                }            }            // Bind the workspace            bindWorkspace();        }

因为WorkspaceLoaded=false,所以会调用loadWorkspace()读取内容数据,等数据读取完毕之后,再调用bindWorkspace()将数据

加载到Workspace中。

[java] view plaincopyprint?
  1. private void loadWorkspace() {  
  2.             ......  
  3.   
  4.             //存放container为CONTAINER_DESKTOP和CONTAINER_HOTSEAT类型的item  
  5.             sWorkspaceItems.clear();  
  6.               
  7.             //存放所有的AppWidget类型   
  8.             sAppWidgets.clear();  
  9.   
  10.             //存放的FolderInfo.id和FolderInfo组成的映射对   
  11.             sFolders.clear();  
  12.   
  13.             //所有的item的id和ItemInfo组成的映射对   
  14.             sItemsIdMap.clear();  
  15.             sDbIconCache.clear();  
  16.   
  17.             final ArrayList<Long> itemsToRemove = new ArrayList<Long>();  
  18.   
  19.             final Cursor c = contentResolver.query(  
  20.                     LauncherSettings.Favorites.CONTENT_URI, nullnullnullnull);  
  21.   
  22.             // +1 for the hotseat (it can be larger than the workspace)  
  23.             // Load workspace in reverse order to ensure that latest items are loaded first (and  
  24.             // before any earlier duplicates)   
  25.             //代表屏幕中的每一个单位的方格是否被占用。   
  26.             //第一维表示分屏的序号,其中最后一个代表Hotseat   
  27.             //第二维表示x方向方格的序号   
  28.             //第三维表示y方向方格的序号   
  29.             final ItemInfo occupied[][][] =  
  30.                     new ItemInfo[Launcher.SCREEN_COUNT + 1][mCellCountX + 1][mCellCountY + 1];  
  31.   
  32.             try {  
  33.                 ......  
  34.   
  35.                 while (!mStopped && c.moveToNext()) {  
  36.                     try {  
  37.                         int itemType = c.getInt(itemTypeIndex);  
  38.   
  39.                         switch (itemType) {  
  40.                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:  
  41.                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:  
  42.                             intentDescription = c.getString(intentIndex);  
  43.                             try {  
  44.                                 intent = Intent.parseUri(intentDescription, 0);  
  45.                             } catch (URISyntaxException e) {  
  46.                                 continue;  
  47.                             }  
  48.   
  49.                             if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {  
  50.                                 info = getShortcutInfo(manager, intent, context, c, iconIndex,  
  51.                                         titleIndex, mLabelCache);  
  52.                             } else {  
  53.                                 info = getShortcutInfo(c, context, iconTypeIndex,  
  54.                                         iconPackageIndex, iconResourceIndex, iconIndex,  
  55.                                         titleIndex);  
  56.                             }  
  57.   
  58.                             if (info != null) {  
  59.                                 ......  
  60.   
  61.                                 // check & update map of what's occupied  
  62.                                 //检查这个item所占的空间是否空闲,true表示空闲  
  63.                                 if (!checkItemPlacement(occupied, info)) {  
  64.                                     break;  
  65.                                 }  
  66.   
  67.                                 switch (container) {  
  68.                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:  
  69.                                 case LauncherSettings.Favorites.CONTAINER_HOTSEAT:  
  70.                                     //当加载的item类型为ITEM_TYPE_APPLICATION或者ITEM_TYPE_SHORTCUT  
  71.                                     //并且所属的container为CONTAINER_DESKTOP或者CONTAINER_HOTSEAT时  
  72.                                     //将其添加到sWorkspaceItems中  
  73.                                     sWorkspaceItems.add(info);  
  74.                                     break;  
  75.                                 default:  
  76.                                     // Item is in a user folder  
  77.                                     //如果item的container不是上述两者,则代表它处于一个folder中  
  78.                                     //将其添加到所属的folderInfo中  
  79.                                     FolderInfo folderInfo =  
  80.                                             findOrMakeFolder(sFolders, container);  
  81.                                     folderInfo.add(info);  
  82.                                     break;  
  83.                                 }  
  84.                                 //所有的ITEM_TYPE_APPLICATION和ITEM_TYPE_SHORTCUT类型的item都需要  
  85.                                 //加入到sItemsIdMap的映射对中。  
  86.                                 sItemsIdMap.put(info.id, info);  
  87.   
  88.                                 // now that we've loaded everthing re-save it with the  
  89.                                 // icon in case it disappears somehow.  
  90.                                 queueIconToBeChecked(sDbIconCache, info, c, iconIndex);  
  91.                             } else {  
  92.                                 // Failed to load the shortcut, probably because the  
  93.                                 // activity manager couldn't resolve it (maybe the app  
  94.                                 // was uninstalled), or the db row was somehow screwed up.  
  95.                                 // Delete it.  
  96.                                 id = c.getLong(idIndex);  
  97.                                 Log.e(TAG, "Error loading shortcut " + id + ", removing it");  
  98.                                 contentResolver.delete(LauncherSettings.Favorites.getContentUri(  
  99.                                             id, false), nullnull);  
  100.                             }  
  101.                             break;  
  102.   
  103.                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:  
  104.                             id = c.getLong(idIndex);  
  105.                             FolderInfo folderInfo = findOrMakeFolder(sFolders, id);  
  106.                             .....  
  107.                             // check & update map of what's occupied  
  108.                             if (!checkItemPlacement(occupied, folderInfo)) {  
  109.                                 break;  
  110.                             }  
  111.                             switch (container) {  
  112.                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:  
  113.                                 case LauncherSettings.Favorites.CONTAINER_HOTSEAT:  
  114.                                     //folderInfo类型的item也需要添加到sWorkspaceItems中  
  115.                                     sWorkspaceItems.add(folderInfo);  
  116.                                     break;  
  117.                             }  
  118.                             //添加到sItemsIdMap映射对中   
  119.                             sItemsIdMap.put(folderInfo.id, folderInfo);  
  120.                             //添加到sFolder映射对中   
  121.                             sFolders.put(folderInfo.id, folderInfo);  
  122.                             break;  
  123.   
  124.                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:  
  125.                             // Read all Launcher-specific widget details  
  126.                             int appWidgetId = c.getInt(appWidgetIdIndex);  
  127.                             id = c.getLong(idIndex);  
  128.   
  129.                             final AppWidgetProviderInfo provider =  
  130.                                     widgets.getAppWidgetInfo(appWidgetId);  
  131.   
  132.                             if (!isSafeMode && (provider == null || provider.provider == null ||  
  133.                                     provider.provider.getPackageName() == null)) {  
  134.                                 ......  
  135.                                 itemsToRemove.add(id);  
  136.                             } else {  
  137.                                 appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);  
  138.                                 ......  
  139.   
  140.                                 container = c.getInt(containerIndex);  
  141.                                 ......  
  142.                                 appWidgetInfo.container = c.getInt(containerIndex);  
  143.   
  144.                                 // check & update map of what's occupied  
  145.                                 if (!checkItemPlacement(occupied, appWidgetInfo)) {  
  146.                                     break;  
  147.                                 }  
  148.                                 //添加到sItemsIdMap映射对   
  149.                                 sItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);  
  150.                                 //添加到sAppWidgets   
  151.                                 sAppWidgets.add(appWidgetInfo);  
  152.                             }  
  153.                             break;  
  154.                         }  
  155.                     } catch (Exception e) {  
  156.                         ......  
  157.                     }  
  158.                 }  
  159.             } finally {  
  160.                 c.close();  
  161.             }  
  162.   
  163.             ......  
  164.         }  
private void loadWorkspace() {            ......            //存放container为CONTAINER_DESKTOP和CONTAINER_HOTSEAT类型的item            sWorkspaceItems.clear();                        //存放所有的AppWidget类型            sAppWidgets.clear();            //存放的FolderInfo.id和FolderInfo组成的映射对            sFolders.clear();            //所有的item的id和ItemInfo组成的映射对            sItemsIdMap.clear();            sDbIconCache.clear();            final ArrayList<Long> itemsToRemove = new ArrayList<Long>();            final Cursor c = contentResolver.query(                    LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);            // +1 for the hotseat (it can be larger than the workspace)            // Load workspace in reverse order to ensure that latest items are loaded first (and            // before any earlier duplicates)            //代表屏幕中的每一个单位的方格是否被占用。            //第一维表示分屏的序号,其中最后一个代表Hotseat            //第二维表示x方向方格的序号            //第三维表示y方向方格的序号            final ItemInfo occupied[][][] =                    new ItemInfo[Launcher.SCREEN_COUNT + 1][mCellCountX + 1][mCellCountY + 1];            try {                ......                while (!mStopped && c.moveToNext()) {                    try {                        int itemType = c.getInt(itemTypeIndex);                        switch (itemType) {                        case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                            intentDescription = c.getString(intentIndex);                            try {                                intent = Intent.parseUri(intentDescription, 0);                            } catch (URISyntaxException e) {                                continue;                            }                            if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {                                info = getShortcutInfo(manager, intent, context, c, iconIndex,                                        titleIndex, mLabelCache);                            } else {                                info = getShortcutInfo(c, context, iconTypeIndex,                                        iconPackageIndex, iconResourceIndex, iconIndex,                                        titleIndex);                            }                            if (info != null) {                                ......                                // check & update map of what's occupied                                //检查这个item所占的空间是否空闲,true表示空闲                                if (!checkItemPlacement(occupied, info)) {                                    break;                                }                                switch (container) {                                case LauncherSettings.Favorites.CONTAINER_DESKTOP:                                case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                                    //当加载的item类型为ITEM_TYPE_APPLICATION或者ITEM_TYPE_SHORTCUT                                    //并且所属的container为CONTAINER_DESKTOP或者CONTAINER_HOTSEAT时                                    //将其添加到sWorkspaceItems中                                    sWorkspaceItems.add(info);                                    break;                                default:                                    // Item is in a user folder                                    //如果item的container不是上述两者,则代表它处于一个folder中                                    //将其添加到所属的folderInfo中                                    FolderInfo folderInfo =                                            findOrMakeFolder(sFolders, container);                                    folderInfo.add(info);                                    break;                                }                                //所有的ITEM_TYPE_APPLICATION和ITEM_TYPE_SHORTCUT类型的item都需要                                //加入到sItemsIdMap的映射对中。                                sItemsIdMap.put(info.id, info);                                // now that we've loaded everthing re-save it with the                                // icon in case it disappears somehow.                                queueIconToBeChecked(sDbIconCache, info, c, iconIndex);                            } else {                                // Failed to load the shortcut, probably because the                                // activity manager couldn't resolve it (maybe the app                                // was uninstalled), or the db row was somehow screwed up.                                // Delete it.                                id = c.getLong(idIndex);                                Log.e(TAG, "Error loading shortcut " + id + ", removing it");                                contentResolver.delete(LauncherSettings.Favorites.getContentUri(                                            id, false), null, null);                            }                            break;                        case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            id = c.getLong(idIndex);                            FolderInfo folderInfo = findOrMakeFolder(sFolders, id);                            .....                            // check & update map of what's occupied                            if (!checkItemPlacement(occupied, folderInfo)) {                                break;                            }                            switch (container) {                                case LauncherSettings.Favorites.CONTAINER_DESKTOP:                                case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                                    //folderInfo类型的item也需要添加到sWorkspaceItems中                                    sWorkspaceItems.add(folderInfo);                                    break;                            }                            //添加到sItemsIdMap映射对中                            sItemsIdMap.put(folderInfo.id, folderInfo);                            //添加到sFolder映射对中                            sFolders.put(folderInfo.id, folderInfo);                            break;                        case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                            // Read all Launcher-specific widget details                            int appWidgetId = c.getInt(appWidgetIdIndex);                            id = c.getLong(idIndex);                            final AppWidgetProviderInfo provider =                                    widgets.getAppWidgetInfo(appWidgetId);                            if (!isSafeMode && (provider == null || provider.provider == null ||                                    provider.provider.getPackageName() == null)) {                                ......                                itemsToRemove.add(id);                            } else {                                appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);                                ......                                container = c.getInt(containerIndex);                                ......                                appWidgetInfo.container = c.getInt(containerIndex);                                // check & update map of what's occupied                                if (!checkItemPlacement(occupied, appWidgetInfo)) {                                    break;                                }                                //添加到sItemsIdMap映射对                                sItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                                //添加到sAppWidgets                                sAppWidgets.add(appWidgetInfo);                            }                            break;                        }                    } catch (Exception e) {                        ......                    }                }            } finally {                c.close();            }            ......        }

 

loadWorkspace的工作就是从ContentProvider获取指定URI中的数据,并将它们分类存放到指定的数据结构中。分类的标准有两条:1、item的类型。包括ITEM_TYPE_APPLICATION  ,ITEM_TYPE_SHORTCUT  ,ITEM_TYPE_FOLDER,ITEM_TYPE_APPWIDGET四类。2、item所属的容器。包括CONTAINER_DESKTOP,

CONTAINER_HOTSEAT以及其它(主要指文件夹)。LauncherModel在读取完数据之后,通过LauncherModel.bindWorkspace()将数据传给到Launcher。进入LauncherModel.bindWorkspace()中:

[java] view plaincopyprint?
  1. private void bindWorkspace() {  
  2.            ......  
  3.            mHandler.post(new Runnable() {  
  4.                public void run() {  
  5.                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  6.                    if (callbacks != null) {  
  7.                        //开始绑定   
  8.                        callbacks.startBinding();  
  9.                    }  
  10.                }  
  11.            });  
  12.   
  13.            ......  
  14.            for (int i=0; i<N; i+=ITEMS_CHUNK) {  
  15.                final int start = i;  
  16.                final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);  
  17.                mHandler.post(new Runnable() {  
  18.                    public void run() {  
  19.                        Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  20.                        if (callbacks != null) {  
  21.                            //绑定application、shortcut、folder三种内容  
  22.                            callbacks.bindItems(workspaceItems, start, start+chunkSize);  
  23.                        }  
  24.                    }  
  25.                });  
  26.            }  
  27.            ......  
  28.            mHandler.post(new Runnable() {  
  29.                public void run() {  
  30.                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  31.                    if (callbacks != null) {  
  32.                        //绑定folder   
  33.                        callbacks.bindFolders(folders);  
  34.                    }  
  35.                }  
  36.            });  
  37.            ......  
  38.            for (int i=0; i<N; i++) {  
  39.                final LauncherAppWidgetInfo widget = sAppWidgets.get(i);  
  40.                if (widget.screen == currentScreen) {  
  41.                    mHandler.post(new Runnable() {  
  42.                        public void run() {  
  43.                            Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  44.                            if (callbacks != null) {  
  45.                                //绑定当前屏的AppWidget  
  46.                                callbacks.bindAppWidget(widget);  
  47.                            }  
  48.                        }  
  49.                    });  
  50.                }  
  51.            }  
  52.             
  53.            for (int i=0; i<N; i++) {  
  54.                final LauncherAppWidgetInfo widget = sAppWidgets.get(i);  
  55.                if (widget.screen != currentScreen) {  
  56.                    mHandler.post(new Runnable() {  
  57.                        public void run() {  
  58.                            Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  59.                            if (callbacks != null) {  
  60.                                //绑定其它屏的AppWidget   
  61.                                callbacks.bindAppWidget(widget);  
  62.                            }  
  63.                        }  
  64.                    });  
  65.                }  
  66.            }  
  67.             
  68.            mHandler.post(new Runnable() {  
  69.                public void run() {  
  70.                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  71.                    if (callbacks != null) {  
  72.                        //结束绑定   
  73.                        callbacks.finishBindingItems();  
  74.                    }  
  75.                }  
  76.            });  
  77.            ......  
  78.        }  
 private void bindWorkspace() {            ......            mHandler.post(new Runnable() {                public void run() {                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);                    if (callbacks != null) {                        //开始绑定                        callbacks.startBinding();                    }                }            });            ......            for (int i=0; i<N; i+=ITEMS_CHUNK) {                final int start = i;                final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                mHandler.post(new Runnable() {                    public void run() {                        Callbacks callbacks = tryGetCallbacks(oldCallbacks);                        if (callbacks != null) {                            //绑定application、shortcut、folder三种内容                            callbacks.bindItems(workspaceItems, start, start+chunkSize);                        }                    }                });            }            ......            mHandler.post(new Runnable() {                public void run() {                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);                    if (callbacks != null) {                        //绑定folder                        callbacks.bindFolders(folders);                    }                }            });            ......            for (int i=0; i<N; i++) {                final LauncherAppWidgetInfo widget = sAppWidgets.get(i);                if (widget.screen == currentScreen) {                    mHandler.post(new Runnable() {                        public void run() {                            Callbacks callbacks = tryGetCallbacks(oldCallbacks);                            if (callbacks != null) {                                //绑定当前屏的AppWidget                                callbacks.bindAppWidget(widget);                            }                        }                    });                }            }                       for (int i=0; i<N; i++) {                final LauncherAppWidgetInfo widget = sAppWidgets.get(i);                if (widget.screen != currentScreen) {                    mHandler.post(new Runnable() {                        public void run() {                            Callbacks callbacks = tryGetCallbacks(oldCallbacks);                            if (callbacks != null) {                                //绑定其它屏的AppWidget                                callbacks.bindAppWidget(widget);                            }                        }                    });                }            }                       mHandler.post(new Runnable() {                public void run() {                    Callbacks callbacks = tryGetCallbacks(oldCallbacks);                    if (callbacks != null) {                        //结束绑定                        callbacks.finishBindingItems();                    }                }            });            ......        }

 

 

可以看到,Launcher的内容绑定分为五步:分别对应着startBinding()、bindItems()、bindFolders()、bindAppWidgets()、finishBindingItems()的调用

Step1:调用Callbacks.startBinding()

由于Launcher实现了Callbacks接口,Launcher中的startBinding()被调用,进入Launcher.startBinding();

[java] view plaincopyprint?
  1. /** 
  2.  * Refreshes the shortcuts shown on the workspace. 
  3.  * 
  4.  * Implementation of the method from LauncherModel.Callbacks. 
  5.  */  
  6. public void startBinding() {  
  7.     final Workspace workspace = mWorkspace;  
  8.   
  9.     mWorkspace.clearDropTargets();  
  10.     int count = workspace.getChildCount();  
  11.     for (int i = 0; i < count; i++) {  
  12.         // Use removeAllViewsInLayout() to avoid an extra requestLayout() and invalidate().  
  13.         final CellLayout layoutParent = (CellLayout) workspace.getChildAt(i);  
  14.         layoutParent.removeAllViewsInLayout();  
  15.     }  
  16.     if (mHotseat != null) {  
  17.         mHotseat.resetLayout();  
  18.     }  
  19. }  
    /**     * Refreshes the shortcuts shown on the workspace.     *     * Implementation of the method from LauncherModel.Callbacks.     */    public void startBinding() {        final Workspace workspace = mWorkspace;        mWorkspace.clearDropTargets();        int count = workspace.getChildCount();        for (int i = 0; i < count; i++) {            // Use removeAllViewsInLayout() to avoid an extra requestLayout() and invalidate().            final CellLayout layoutParent = (CellLayout) workspace.getChildAt(i);            layoutParent.removeAllViewsInLayout();        }        if (mHotseat != null) {            mHotseat.resetLayout();        }    }

从方法中的内容我们可以看到,当被通知开始加载Workspace中内容时,Launcher重置了Workspace中的内容,Hotseat也通过resetLayout方法进行重置。

[java] view plaincopyprint?
  1. void resetLayout() {  
  2.     mContent.removeAllViewsInLayout();  
  3.   
  4.     // Add the Apps button   
  5.     Context context = getContext();  
  6.     LayoutInflater inflater = LayoutInflater.from(context);  
  7.     BubbleTextView allAppsButton = (BubbleTextView)  
  8.             inflater.inflate(R.layout.application, mContent, false);  
  9.     ......  
  10.   
  11.     // Note: We do this to ensure that the hotseat is always laid out in the orientation of  
  12.     // the hotseat in order regardless of which orientation they were added  
  13.     int x = getCellXFromOrder(sAllAppsButtonRank);  
  14.     int y = getCellYFromOrder(sAllAppsButtonRank);  
  15.     mContent.addViewToCellLayout(allAppsButton, -10new CellLayout.LayoutParams(x,y,1,1),  
  16.             true);  
  17. }  
    void resetLayout() {        mContent.removeAllViewsInLayout();        // Add the Apps button        Context context = getContext();        LayoutInflater inflater = LayoutInflater.from(context);        BubbleTextView allAppsButton = (BubbleTextView)                inflater.inflate(R.layout.application, mContent, false);        ......        // Note: We do this to ensure that the hotseat is always laid out in the orientation of        // the hotseat in order regardless of which orientation they were added        int x = getCellXFromOrder(sAllAppsButtonRank);        int y = getCellYFromOrder(sAllAppsButtonRank);        mContent.addViewToCellLayout(allAppsButton, -1, 0, new CellLayout.LayoutParams(x,y,1,1),                true);    }

Hotseat中清空了装载的内容,然后重新加载allAppsButton。从这里也可以看到allAppsButton是固定到了Hotseat中,不同于Hotseat中的其他控件。

 

Step2:调用Callbacks.bindItems(ArrayList<ItemInfo> shortcuts, int start, int end)

准备工作完成之后,现在可以开始正式的加载工作了,首先被调用的是bindItems()方法

[java] view plaincopyprint?
  1.  /** 
  2.  * Bind the items start-end from the list. 
  3.  * 
  4.  * Implementation of the method from LauncherModel.Callbacks. 
  5.  */  
  6. public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end) {  
  7.     setLoadOnResume();  
  8.   
  9.     final Workspace workspace = mWorkspace;  
  10.     for (int i=start; i<end; i++) {  
  11.         final ItemInfo item = shortcuts.get(i);  
  12.         ......  
  13.         switch (item.itemType) {  
  14.             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:  
  15.             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:  
  16.                 View shortcut = createShortcut((ShortcutInfo)item);  
  17.                 workspace.addInScreen(shortcut, item.container, item.screen, item.cellX,  
  18.                         item.cellY, 11false);  
  19.                 break;  
  20.             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:  
  21.                 FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,  
  22.                         (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),  
  23.                         (FolderInfo) item, mIconCache);  
  24.                 workspace.addInScreen(newFolder, item.container, item.screen, item.cellX,  
  25.                         item.cellY, 11false);  
  26.                 break;  
  27.         }  
  28.     }  
  29.     workspace.requestLayout();  
  30. }  
     /**     * Bind the items start-end from the list.     *     * Implementation of the method from LauncherModel.Callbacks.     */    public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end) {        setLoadOnResume();        final Workspace workspace = mWorkspace;        for (int i=start; i<end; i++) {            final ItemInfo item = shortcuts.get(i);            ......            switch (item.itemType) {                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                    View shortcut = createShortcut((ShortcutInfo)item);                    workspace.addInScreen(shortcut, item.container, item.screen, item.cellX,                            item.cellY, 1, 1, false);                    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();    }

通过这个方法,将application、shortcut、folder三种item通过Workspace.addInScreen()添加到Workspace中

[java] view plaincopyprint?
  1. /** 
  2.  * Adds the specified child in the specified screen. The position and dimension of 
  3.  * the child are defined by x, y, spanX and spanY. 
  4.  * 
  5.  * @param child The child to add in one of the workspace's screens. 
  6.  * @param screen The screen in which to add the child. 
  7.  * @param x The X position of the child in the screen's grid. 
  8.  * @param y The Y position of the child in the screen's grid. 
  9.  * @param spanX The number of cells spanned horizontally by the child. 
  10.  * @param spanY The number of cells spanned vertically by the child. 
  11.  * @param insert When true, the child is inserted at the beginning of the children list. 
  12.  */  
  13. void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY,  
  14.         boolean insert) {  
  15.     ......  
  16.   
  17.     //Workspace一共有五个分屏,每个分屏是一个CellLayout   
  18.     final CellLayout layout;  
  19.     if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {  
  20.         layout = mLauncher.getHotseat().getLayout();  
  21.         child.setOnKeyListener(null);  
  22.   
  23.         ......  
  24.         if (screen < 0) {  
  25.             screen = mLauncher.getHotseat().getOrderInHotseat(x, y);  
  26.         } else {  
  27.             // Note: We do this to ensure that the hotseat is always laid out in the orientation  
  28.             // of the hotseat in order regardless of which orientation they were added  
  29.             //获取child的位置,返回true添加成功,false失败  
  30.             x = mLauncher.getHotseat().getCellXFromOrder(screen);  
  31.             y = mLauncher.getHotseat().getCellYFromOrder(screen);  
  32.         }  
  33.     } else {  
  34.         // Show folder title if not in the hotseat   
  35.         if (child instanceof FolderIcon) {  
  36.             ((FolderIcon) child).setTextVisible(true);  
  37.         }  
  38.   
  39.         layout = (CellLayout) getChildAt(screen);  
  40.         child.setOnKeyListener(new IconKeyEventListener());  
  41.     }  
  42.   
  43.     CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();  
  44.     if (lp == null) {  
  45.         lp = new CellLayout.LayoutParams(x, y, spanX, spanY);  
  46.     } else {  
  47.         lp.cellX = x;  
  48.         lp.cellY = y;  
  49.         lp.cellHSpan = spanX;  
  50.         lp.cellVSpan = spanY;  
  51.     }  
  52.   
  53.     if (spanX < 0 && spanY < 0) {  
  54.         lp.isLockedToGrid = false;  
  55.     }  
  56.   
  57.     // Get the canonical child id to uniquely represent this view in this screen  
  58.     int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY);  
  59.     boolean markCellsAsOccupied = !(child instanceof Folder);  
  60.     //将child添加到CellLayout中去   
  61.     if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {  
  62.         ......  
  63.     }  
  64.   
  65.     if (!(child instanceof Folder)) {  
  66.         child.setHapticFeedbackEnabled(false);  
  67.         child.setOnLongClickListener(mLongClickListener);  
  68.     }  
  69.     if (child instanceof DropTarget) {  
  70.         mDragController.addDropTarget((DropTarget) child);  
  71.     }  
  72. }  
    /**     * Adds the specified child in the specified screen. The position and dimension of     * the child are defined by x, y, spanX and spanY.     *     * @param child The child to add in one of the workspace's screens.     * @param screen The screen in which to add the child.     * @param x The X position of the child in the screen's grid.     * @param y The Y position of the child in the screen's grid.     * @param spanX The number of cells spanned horizontally by the child.     * @param spanY The number of cells spanned vertically by the child.     * @param insert When true, the child is inserted at the beginning of the children list.     */    void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY,            boolean insert) {        ......        //Workspace一共有五个分屏,每个分屏是一个CellLayout        final CellLayout layout;        if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {            layout = mLauncher.getHotseat().getLayout();            child.setOnKeyListener(null);            ......            if (screen < 0) {                screen = mLauncher.getHotseat().getOrderInHotseat(x, y);            } else {                // Note: We do this to ensure that the hotseat is always laid out in the orientation                // of the hotseat in order regardless of which orientation they were added                //获取child的位置,返回true添加成功,false失败                x = mLauncher.getHotseat().getCellXFromOrder(screen);                y = mLauncher.getHotseat().getCellYFromOrder(screen);            }        } else {            // Show folder title if not in the hotseat            if (child instanceof FolderIcon) {                ((FolderIcon) child).setTextVisible(true);            }            layout = (CellLayout) getChildAt(screen);            child.setOnKeyListener(new IconKeyEventListener());        }        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();        if (lp == null) {            lp = new CellLayout.LayoutParams(x, y, spanX, spanY);        } else {            lp.cellX = x;            lp.cellY = y;            lp.cellHSpan = spanX;            lp.cellVSpan = spanY;        }        if (spanX < 0 && spanY < 0) {            lp.isLockedToGrid = false;        }        // Get the canonical child id to uniquely represent this view in this screen        int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY);        boolean markCellsAsOccupied = !(child instanceof Folder);        //将child添加到CellLayout中去        if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {            ......        }        if (!(child instanceof Folder)) {            child.setHapticFeedbackEnabled(false);            child.setOnLongClickListener(mLongClickListener);        }        if (child instanceof DropTarget) {            mDragController.addDropTarget((DropTarget) child);        }    }

通过addInScreen()就能将child添加到指定的CellLayout中去。CellLayout共有六个,Workspace中五个,Hotseat一个。

 

Step3:调用Callbacks.bindFolders(HashMap<Long, FolderInfo> folders)

Launcher.bindFolders()中的代码只有三行:

[java] view plaincopyprint?
  1. public void bindFolders(HashMap<Long, FolderInfo> folders) {  
  2.         setLoadOnResume();  
  3.         sFolders.clear();  
  4.         sFolders.putAll(folders);  
  5.     }  
public void bindFolders(HashMap<Long, FolderInfo> folders) {        setLoadOnResume();        sFolders.clear();        sFolders.putAll(folders);    }

获取到当前的Folder的映射表。

 

Step4:调用Callbacks.bindAppWidgets(LauncherAppWidgetInfo item)

现在开始加载AppWidget到Workspace:

[java] view plaincopyprint?
  1.  /** 
  2.  * Add the views for a widget to the workspace. 
  3.  * 
  4.  * Implementation of the method from LauncherModel.Callbacks. 
  5.  */  
  6. public void bindAppWidget(LauncherAppWidgetInfo item) {  
  7.     setLoadOnResume();  
  8.   
  9.     ......  
  10.     final Workspace workspace = mWorkspace;  
  11.   
  12.     final int appWidgetId = item.appWidgetId;  
  13.     final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);  
  14.     ......  
  15.   
  16.     item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);  
  17.   
  18.     item.hostView.setAppWidget(appWidgetId, appWidgetInfo);  
  19.     item.hostView.setTag(item);  
  20.   
  21.     workspace.addInScreen(item.hostView, item.container, item.screen, item.cellX,  
  22.             item.cellY, item.spanX, item.spanY, false);  
  23.   
  24.     addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);  
  25.   
  26.     workspace.requestLayout();  
  27.   
  28.     ......  
  29. }  
     /**     * Add the views for a widget to the workspace.     *     * Implementation of the method from LauncherModel.Callbacks.     */    public void bindAppWidget(LauncherAppWidgetInfo item) {        setLoadOnResume();        ......        final Workspace workspace = mWorkspace;        final int appWidgetId = item.appWidgetId;        final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);        ......        item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);        item.hostView.setAppWidget(appWidgetId, appWidgetInfo);        item.hostView.setTag(item);        workspace.addInScreen(item.hostView, item.container, item.screen, item.cellX,                item.cellY, item.spanX, item.spanY, false);        addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);        workspace.requestLayout();        ......    }

先获取到AppWidget的相关信息之后,调用Workspace.addInScreen()添加到Workspace。AppWidget是Android系统的一大特色,可

以在桌面上快捷的获取实时信息和对一些指定应用进行控制。AppWidget是需要自动更新的(如果应用中设置了更新),因此除了

将其添加到桌面我们需要更具需要设置自动更新。进而调用addWidgetToAutoAdvanceifNeeded()来实现此功能,关于如何实现自动

新AppWidget的话题,本文暂不做分析。bindAppWidgets()一共被调用两次,这样做的目的是增加流畅感,第一次调用的时候为

当前显示的分屏添加AppWidget,第二次调用的时候为其他未显示的分屏添加AppWidget。这样就给用户带来了一种流畅的用户体验。

Step5:调用Callbacks.finishBindingItems()

通过上面的操作,所有item就已经悉数被添加到Workspace当中,此时调用finishBindingItems()通知Launcher添加完毕。

[java] view plaincopyprint?
  1. /** 
  2. * Callback saying that there aren't any more items to bind. 
  3. * 
  4. * Implementation of the method from LauncherModel.Callbacks. 
  5. */  
  6. ublic void finishBindingItems() {  
  7.    setLoadOnResume();  
  8.    ......  
  9.    mWorkspaceLoading = false;  
  10.   
  11.    // If we received the result of any pending adds while the loader was running (e.g. the  
  12.    // widget configuration forced an orientation change), process them now.  
  13.    for (int i = 0; i < sPendingAddList.size(); i++) {  
  14.        completeAdd(sPendingAddList.get(i));  
  15.    }  
  16.    sPendingAddList.clear();  
  17.    ......  
  18.    mWorkspace.post(mBuildLayersRunnable);  
     /**     * Callback saying that there aren't any more items to bind.     *     * Implementation of the method from LauncherModel.Callbacks.     */    public void finishBindingItems() {        setLoadOnResume();        ......        mWorkspaceLoading = false;        // If we received the result of any pending adds while the loader was running (e.g. the        // widget configuration forced an orientation change), process them now.        for (int i = 0; i < sPendingAddList.size(); i++) {            completeAdd(sPendingAddList.get(i));        }        sPendingAddList.clear();        ......        mWorkspace.post(mBuildLayersRunnable);    }

当Workspace正在加载的时候,有一些操作发生却还未执行,在finishBindingItems()中来执行这些操作,调用completeAdd()来完成

还未来得及完成的操作。紧接着又向Workspace的消息队列里加入了mBuildLayersRunnable,mBuildLayersRunnable是Runnable的

一个实例,它的功能就是迫使每个View都完成渲染的工作,即及时的现实到桌面中现好了所有需要的内容了。那下一步就是需要向

All Apps页中加载内容了。

二、AllApps的内容加载

回到mLoaderTask.run()方法中,当bindWorkspace()执行结束之后,并通过waitForIdle()确认加载完成之后,就会调用

loadAndBindAllApps()来为AllApps页面加载内容。

[java] view plaincopyprint?
  1. private void loadAndBindAllApps() {  
  2.             ......  
  3.             if (!mAllAppsLoaded) {  
  4.                 //批量加载app和widget信息   
  5.                 loadAllAppsByBatch();  
  6.                 ......  
  7.             } else {  
  8.                 //无需重复加载,直接绑定   
  9.                 onlyBindAllApps();  
  10.             }  
  11.         }  
private void loadAndBindAllApps() {            ......            if (!mAllAppsLoaded) {                //批量加载app和widget信息                loadAllAppsByBatch();                ......            } else {                //无需重复加载,直接绑定                onlyBindAllApps();            }        }

 

AllApps中的加载过程和Workspace中的加载过程大致是相同的,只是All Apps的加载和绑定过程被放到同一个方loadAllAppsByBatch()中执行:

[java] view plaincopyprint?
  1. /** 
  2.  *批量的向加载内容 
  3.  */  
  4.  private void loadAllAppsByBatch() {  
  5.      ......  
  6.      //设置Intent的action为ACTION_MAIN,category为CATEGORY_LAUNCHER  
  7.      //这样就筛选出桌面上显示的启动项了。   
  8.      final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  9.      mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  
  10.   
  11.      final PackageManager packageManager = mContext.getPackageManager();  
  12.      List<ResolveInfo> apps = null;  
  13.   
  14.      int N = Integer.MAX_VALUE;  
  15.   
  16.      int startIndex;  
  17.      int i=0;  
  18.      int batchSize = -1;  
  19.      while (i < N && !mStopped) {  
  20.          if (i == 0) {  
  21.              mAllAppsList.clear();  
  22.              ......  
  23.              //查询所有应该在桌面上显示的app   
  24.              apps = packageManager.queryIntentActivities(mainIntent, 0);  
  25.              ......  
  26.                
  27.              N = apps.size();  
  28.              ......  
  29.              if (mBatchSize == 0) {  
  30.                  //mBatchSize==0表示一次性加载所有的应用   
  31.                  batchSize = N;  
  32.              } else {  
  33.                  batchSize = mBatchSize;  
  34.              }  
  35.   
  36.              ......  
  37.              //将获取到的app的信息按名字进行排序   
  38.              Collections.sort(apps,  
  39.                      new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));  
  40.              ......  
  41.          }  
  42.   
  43.          ......  
  44.   
  45.          startIndex = i;  
  46.          //添加一批应用信息到mAllAppsList,每一批添加N个   
  47.          for (int j=0; i<N && j<batchSize; j++) {  
  48.              // This builds the icon bitmaps.   
  49.              mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),  
  50.                      mIconCache, mLabelCache));  
  51.              i++;  
  52.          }  
  53.   
  54.          //i < batchSize表示添加的是第一批信息   
  55.          final boolean first = i <= batchSize;  
  56.          final Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  57.          final ArrayList<ApplicationInfo> added = mAllAppsList.added;  
  58.   
  59.          //每添加完一批之后,将added重新清空   
  60.          mAllAppsList.added = new ArrayList<ApplicationInfo>();  
  61.   
  62.          mHandler.post(new Runnable() {  
  63.              public void run() {  
  64.                  ......  
  65.                  //Launcher实现了Callbacks接口,将获取到的数据回调给Launcher  
  66.                  if (callbacks != null) {  
  67.                      if (first) {  
  68.                          callbacks.bindAllApplications(added);  
  69.                      } else {  
  70.                          callbacks.bindAppsAdded(added);  
  71.                      }  
  72.                      ......  
  73.                  } else {  
  74.                     ......  
  75.                  }  
  76.              }  
  77.          });  
  78.          ......  
  79.      }  
  80.      ......  
  81.  }  
       /**        *批量的向加载内容        */        private void loadAllAppsByBatch() {            ......            //设置Intent的action为ACTION_MAIN,category为CATEGORY_LAUNCHER            //这样就筛选出桌面上显示的启动项了。            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);            final PackageManager packageManager = mContext.getPackageManager();            List<ResolveInfo> apps = null;            int N = Integer.MAX_VALUE;            int startIndex;            int i=0;            int batchSize = -1;            while (i < N && !mStopped) {                if (i == 0) {                    mAllAppsList.clear();                    ......                    //查询所有应该在桌面上显示的app                    apps = packageManager.queryIntentActivities(mainIntent, 0);                    ......                                        N = apps.size();                    ......                    if (mBatchSize == 0) {                        //mBatchSize==0表示一次性加载所有的应用                        batchSize = N;                    } else {                        batchSize = mBatchSize;                    }                    ......                    //将获取到的app的信息按名字进行排序                    Collections.sort(apps,                            new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));                    ......                }                ......                startIndex = i;                //添加一批应用信息到mAllAppsList,每一批添加N个                for (int j=0; i<N && j<batchSize; j++) {                    // This builds the icon bitmaps.                    mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),                            mIconCache, mLabelCache));                    i++;                }                //i < batchSize表示添加的是第一批信息                final boolean first = i <= batchSize;                final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                final ArrayList<ApplicationInfo> added = mAllAppsList.added;                //每添加完一批之后,将added重新清空                mAllAppsList.added = new ArrayList<ApplicationInfo>();                mHandler.post(new Runnable() {                    public void run() {                        ......                        //Launcher实现了Callbacks接口,将获取到的数据回调给Launcher                        if (callbacks != null) {                            if (first) {                                callbacks.bindAllApplications(added);                            } else {                                callbacks.bindAppsAdded(added);                            }                            ......                        } else {                           ......                        }                    }                });                ......            }            ......        }

 

 

过程还是挺简单的,首先当然是查询所有的App了,通过向PackagedManager发送指定的Intent就能够获得安装好的应用的信息。查

询完毕之后,将数据封装到ArrayList<ApplicationInfo>对象中,然后通过Callbacks.bindAllApplication()或Callbacks.bindAppsAdded()

将数据传给Launcher。Launcher中的操作也比加载Workspace时简单多,毕竟这里只需要加载Icon。

[java] view plaincopyprint?
  1. /** 
  2.   * Add the icons for all apps. 
  3.   * 
  4.   * Implementation of the method from LauncherModel.Callbacks. 
  5.   */  
  6.  public void bindAllApplications(final ArrayList<ApplicationInfo> apps) {  
  7.      ......  
  8.      // We just post the call to setApps so the user sees the progress bar  
  9.      // disappear-- otherwise, it just looks like the progress bar froze  
  10.      // which doesn't look great   
  11.      mAppsCustomizeTabHost.post(new Runnable() {  
  12.          public void run() {  
  13.              if (mAppsCustomizeContent != null) {  
  14.                  mAppsCustomizeContent.setApps(apps);  
  15.              }  
  16.          }  
  17.      });  
  18.  }  
   /**     * Add the icons for all apps.     *     * Implementation of the method from LauncherModel.Callbacks.     */    public void bindAllApplications(final ArrayList<ApplicationInfo> apps) {        ......        // We just post the call to setApps so the user sees the progress bar        // disappear-- otherwise, it just looks like the progress bar froze        // which doesn't look great        mAppsCustomizeTabHost.post(new Runnable() {            public void run() {                if (mAppsCustomizeContent != null) {                    mAppsCustomizeContent.setApps(apps);                }            }        });    }

 

 

 

[java] view plaincopyprint?
  1. /** 
  2.  * A package was installed. 
  3.  * 
  4.  * Implementation of the method from LauncherModel.Callbacks. 
  5.  */  
  6. public void bindAppsAdded(ArrayList<ApplicationInfo> apps) {  
  7.     setLoadOnResume();  
  8.     ......  
  9.   
  10.     if (mAppsCustomizeContent != null) {  
  11.         mAppsCustomizeContent.addApps(apps);  
  12.     }  
  13. }  
    /**     * A package was installed.     *     * Implementation of the method from LauncherModel.Callbacks.     */    public void bindAppsAdded(ArrayList<ApplicationInfo> apps) {        setLoadOnResume();        ......        if (mAppsCustomizeContent != null) {            mAppsCustomizeContent.addApps(apps);        }    }

这样All Apps页面的加载也完成了。

 

到这一步,Launcher内容的加载过程也就完成了。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 怀孕肌酐偏高210怎么办 孕晚期酮体2是怎么办 怀孕8个月贫血怎么办94 超了月经五天了怎么办 产检尿检有问题怎么办 42天了还有恶露怎么办 恶露42天不干净怎么办 产后42天同房出血怎么办 50多天还有恶露怎么办 55天恶露没干净怎么办 恶露56天没干净怎么办 孕晚期甘胆酸高怎么办 怀孕40周还没入盆怎么办 新买的被子臭味怎么办 被套洗了有异味怎么办 被子上有狐臭味怎么办 尿葡萄糖3个加怎么办 孕妇维c高了怎么办 孕妇吃了维生素c怎么办 尿潜血1十偏高怎么办 培养出b族链球菌怎么办 培养出b群链球菌怎么办 怀孕32周血压高怎么办 白带白细胞2个加怎么办 怀孕尿糖3个加号怎么办 黄疸高怎么办要怎么降 孕40周尿蛋白高怎么办 怀孕了尿蛋白高怎么办 尿蛋白2个加号怎么办 尿蛋白二个加号怎么办 孕妇尿蛋白3是怎么办 尿蛋白高 体检要怎么办 小三阳肝功能正常dna阳性怎么办 维生素c弱阳性该怎么办 体检ph值低了怎么办呀 明矾当泡茶喝了怎么办 怀孕三个月胎儿停止发育怎么办 怀孕ph值是5.0怎么办 孕25周胎盘前置怎么办 6个月孕妇贫血怎么办 24小时尿蛋白175怎么办