Launcher app数据加载流程
Launcher是桌面,是用户第一眼看到的app应用,所有的应用都是现实通过Launcher管理显示在桌面上的!当app应用很多的时候,数据是怎么样加载的呢!我说一说单层桌面加载的流程上图是双层数据加载流程,单层的只要看左边四个加Launcher就可以了
首先我们要找到桌面的入口在哪里!就在Launcher oncreate();
@Overrideprotected void onCreate(Bundle savedInstanceState) {............super.onCreate(savedInstanceState);LauncherAppState.setApplicationContext(getApplicationContext());LauncherAppState app = LauncherAppState.getInstance();// Determine the dynamic grid propertiesPoint smallestSize = new Point();Point largestSize = new Point();Point realSize = new Point();Display display = getWindowManager().getDefaultDisplay();display.getCurrentSizeRange(smallestSize, largestSize);display.getRealSize(realSize);DisplayMetrics dm = new DisplayMetrics();display.getMetrics(dm);// Lazy-initialize the dynamic gridDeviceProfile grid = app.initDynamicGrid(this,Math.min(smallestSize.x, smallestSize.y),Math.min(largestSize.x, largestSize.y),realSize.x, realSize.y,dm.widthPixels, dm.heightPixels);// the LauncherApplication should call this, but in case of Instrumentation it might not be present yetmSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(),Context.MODE_PRIVATE);mModel = app.setLauncher(this);mIconCache = app.getIconCache();mDragController = new DragController(this);mInflater = getLayoutInflater();mStats = new Stats(this);mAppWidgetManager = AppWidgetManager.getInstance(this);mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);mAppWidgetHost.startListening();// If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,// this also ensures that any synchronous binding below doesn't re-trigger another// LauncherModel load.mPaused = false;if (PROFILE_STARTUP) {android.os.Debug.startMethodTracing(Environment.getExternalStorageDirectory() + "/launcher");}checkForLocaleChange();setContentView(R.layout.launcher);setupViews();grid.layout(this);registerContentObservers();lockAllApps();mSavedState = savedInstanceState;restoreState(mSavedState);// Update customization drawer _after_ restoring the statesif (mAppsCustomizeContent != null) {mAppsCustomizeContent.onPackagesUpdated(LauncherModel.getSortedWidgetsAndShortcuts(this));}if (PROFILE_STARTUP) {android.os.Debug.stopMethodTracing();}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 foregroundmModel.startLoader(true, mWorkspace.getCurrentPage());}}............}
``在这里面是初始化一些对象,
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());
}
}
这里才是数据加载的入口,mRestoring 是在restoreState()方法置换成true,说明在非正常停止的状态下,所以只要不是系统kill掉,mRestoring始终是false,往下看:sPausedFromUserAction=true:是在用户离开Laucnher,又回到Launcher我们需要异步加载数据,反之,我们加载同步加载这一页的数据,那就进入mModel.startLoader的方法!public void startLoader(boolean isLaunching, int synchronousBindPage) {synchronized (mLock) {if (DEBUG_LOADERS) {Log.d(TAG, "startLoader isLaunching=" + isLaunching);}//ear any deferred bind-runnables from the synchronized load process// We must do this before any loading/binding is scheduled below.mDeferredBindRunnables.clear();// Don't bother to start the thread if we know it's not going to do anythingif (mCallbacks != null && mCallbacks.get() != null) {// If there is already one running, tell it to stop.// also, don't downgrade isLaunching if we're already runningisLaunching = isLaunching || stopLoaderLocked();mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching);if (synchronousBindPage > -1 && mAllAppsLoaded && mWorkspaceLoaded) {mLoaderTask.runBindSynchronousPage(synchronousBindPage);} else {sWorkerThread.setPriority(Thread.NORM_PRIORITY);sWorker.post(mLoaderTask);}}}}
相当于一个同步方法, mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching);这是一个线程,加载数据肯定要用到线程,找到这个类,往里继续跟找到run方法就可以了
public void run() {boolean isUpgrade = false;synchronized (mLock) {mIsLoaderTaskRunning = true;}// Optimize for end-user experience: if the Launcher is up and // running with the// All Apps interface in the foreground, load All Apps first. Otherwise, load the// workspace first (default).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"));Process.setThreadPriority(mIsLaunching? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);}if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");isUpgrade = loadAndBindWorkspace();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");Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);}}waitForIdle();// second stepif (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");loadAndBindAllApps();// Restore the default thread priority after we are done loading itemssynchronized (mLock) {Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);}}// Update the saved icons if necessaryif (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");synchronized (sBgLock) {for (Object key : sBgDbIconCache.keySet()) {updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));}sBgDbIconCache.clear();}if (AppsCustomizePagedView.DISABLE_ALL_APPS) {// Ensure that all the applications that are in the system are// represented on the home screen.if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {verifyApplications();}}// Clear out this reference, otherwise we end up holding it until all of the// callback runnables are done.mContext = null;synchronized (mLock) {// If we are still the last one to be scheduled, remove ourselves.if (mLoaderTask == this) {mLoaderTask = null;}mIsLoaderTaskRunning = false;}}
在上面看到 isUpgrade = loadAndBindWorkspace(); 加载并且绑定桌面;往里面跟进去
private boolean loadAndBindWorkspace() {mIsLoadingAndBindingWorkspace = true;// Load the workspaceif (DEBUG_LOADERS) {Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);}boolean isUpgradePath = false;if (!mWorkspaceLoaded) {isUpgradePath = loadWorkspace();synchronized (LoaderTask.this) {if (mStopped) {return isUpgradePath;}mWorkspaceLoaded = true;}}// Bind the workspacebindWorkspace(-1, isUpgradePath);return isUpgradePath;}
这个方法主要是做mWorkspaceLoaded加载过了就直接绑定bindWorkspace(-1, isUpgradePath);,没有加载就去loadWorkspace()加载桌面,去看看加载桌面;
private boolean loadWorkspace() {final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;final Context context = mContext;final ContentResolver contentResolver = context.getContentResolver();final PackageManager manager = context.getPackageManager();final AppWidgetManager widgets = AppWidgetManager.getInstance(context);final boolean isSafeMode = manager.isSafeMode();LauncherAppState app = LauncherAppState.getInstance();DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();int countX = (int) grid.numColumns;int countY = (int) grid.numRows;// Make sure the default workspace is loaded, if neededLauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);// Check if we need to do any upgrade-path logicboolean loadedOldDb = LauncherAppState.getLauncherProvider().justLoadedOldDb();synchronized (sBgLock) {clearSBgDataStructures();final ArrayList<Long> itemsToRemove = new ArrayList<Long>();final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);final Cursor c = contentResolver.query(contentUri, 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)final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();try {final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);final int appWidgetProviderIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_PROVIDER);final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);//final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);//final int displayModeIndex = c.getColumnIndexOrThrow(// LauncherSettings.Favorites.DISPLAY_MODE);ShortcutInfo info;String intentDescription;LauncherAppWidgetInfo appWidgetInfo;int container;long id;Intent intent;while (!mStopped && c.moveToNext()) {AtomicBoolean deleteOnItemOverlap = new AtomicBoolean(false);try {int itemType = c.getInt(itemTypeIndex);switch (itemType) {case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:id = c.getLong(idIndex);intentDescription = c.getString(intentIndex);try {intent = Intent.parseUri(intentDescription, 0);ComponentName cn = intent.getComponent();if (cn != null && !isValidPackageComponent(manager, cn)) {if (!mAppsCanBeOnRemoveableStorage) {// Log the invalid package, and remove it from the dbLauncher.addDumpLog(TAG, "Invalid package removed: " + cn, true);itemsToRemove.add(id);} else {// If apps can be on external storage, then we just// leave them for the user to remove (maybe add// visual treatment to it)Launcher.addDumpLog(TAG, "Invalid package found: " + cn, true);}continue;}} catch (URISyntaxException e) {Launcher.addDumpLog(TAG, "Invalid uri: " + intentDescription, true);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);// App shortcuts that used to be automatically added to Launcher// didn't always have the correct intent flags set, so do that// hereif (intent.getAction() != null &&intent.getCategories() != null &&intent.getAction().equals(Intent.ACTION_MAIN) &&intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);}}if (info != null) {info.id = id;info.intent = intent;container = c.getInt(containerIndex);info.container = container;info.screenId = c.getInt(screenIndex);info.cellX = c.getInt(cellXIndex);info.cellY = c.getInt(cellYIndex);info.spanX = 1;info.spanY = 1;// Skip loading items that are out of boundsif (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {if (checkItemDimensions(info)) {Launcher.addDumpLog(TAG, "Skipped loading out of bounds shortcut: "+ info + ", " + grid.numColumns + "x" + grid.numRows, true);continue;}}// check & update map of what's occupieddeleteOnItemOverlap.set(false);if (!checkItemPlacement(occupied, info, deleteOnItemOverlap)) {if (deleteOnItemOverlap.get()) {itemsToRemove.add(id);}break;}switch (container) {case LauncherSettings.Favorites.CONTAINER_DESKTOP:case LauncherSettings.Favorites.CONTAINER_HOTSEAT:sBgWorkspaceItems.add(info);break;default:// Item is in a user folderFolderInfo folderInfo =findOrMakeFolder(sBgFolders, container);folderInfo.add(info);break;}sBgItemsIdMap.put(info.id, info);// now that we've loaded everthing re-save it with the// icon in case it disappears somehow.queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);} else {throw new RuntimeException("Unexpected null ShortcutInfo");}break;case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:id = c.getLong(idIndex);FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);folderInfo.title = c.getString(titleIndex);folderInfo.id = id;container = c.getInt(containerIndex);folderInfo.container = container;folderInfo.screenId = c.getInt(screenIndex);folderInfo.cellX = c.getInt(cellXIndex);folderInfo.cellY = c.getInt(cellYIndex);folderInfo.spanX = 1;folderInfo.spanY = 1;// Skip loading items that are out of boundsif (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {if (checkItemDimensions(folderInfo)) {Log.d(TAG, "Skipped loading out of bounds folder");continue;}}// check & update map of what's occupieddeleteOnItemOverlap.set(false);if (!checkItemPlacement(occupied, folderInfo,deleteOnItemOverlap)) {if (deleteOnItemOverlap.get()) {itemsToRemove.add(id);}break;}switch (container) {case LauncherSettings.Favorites.CONTAINER_DESKTOP:case LauncherSettings.Favorites.CONTAINER_HOTSEAT:sBgWorkspaceItems.add(folderInfo);break;}sBgItemsIdMap.put(folderInfo.id, folderInfo);sBgFolders.put(folderInfo.id, folderInfo);break;case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:// Read all Launcher-specific widget detailsint appWidgetId = c.getInt(appWidgetIdIndex);String savedProvider = c.getString(appWidgetProviderIndex);id = c.getLong(idIndex);final AppWidgetProviderInfo provider =widgets.getAppWidgetInfo(appWidgetId);if (!isSafeMode && (provider == null || provider.provider == null ||provider.provider.getPackageName() == null)) {String log = "Deleting widget that isn't installed anymore: id="+ id + " appWidgetId=" + appWidgetId;Log.e(TAG, log);Launcher.addDumpLog(TAG, log, false);itemsToRemove.add(id);} else {appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,provider.provider);appWidgetInfo.id = id;appWidgetInfo.screenId = c.getInt(screenIndex);appWidgetInfo.cellX = c.getInt(cellXIndex);appWidgetInfo.cellY = c.getInt(cellYIndex);appWidgetInfo.spanX = c.getInt(spanXIndex);appWidgetInfo.spanY = c.getInt(spanYIndex);int[] minSpan = Launcher.getMinSpanForWidget(context, provider);appWidgetInfo.minSpanX = minSpan[0];appWidgetInfo.minSpanY = minSpan[1];container = c.getInt(containerIndex);if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {Log.e(TAG, "Widget found where container != " +"CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");continue;}appWidgetInfo.container = c.getInt(containerIndex);// Skip loading items that are out of boundsif (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {if (checkItemDimensions(appWidgetInfo)) {Log.d(TAG, "Skipped loading out of bounds app widget");continue;}}// check & update map of what's occupieddeleteOnItemOverlap.set(false);if (!checkItemPlacement(occupied, appWidgetInfo,deleteOnItemOverlap)) {if (deleteOnItemOverlap.get()) {itemsToRemove.add(id);}break;}String providerName = provider.provider.flattenToString();if (!providerName.equals(savedProvider)) {ContentValues values = new ContentValues();values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,providerName);String where = BaseColumns._ID + "= ?";String[] args = {Integer.toString(c.getInt(idIndex))};contentResolver.update(contentUri, values, where, args);}sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);sBgAppWidgets.add(appWidgetInfo);}break;}} catch (Exception e) {Launcher.addDumpLog(TAG, "Desktop items loading interrupted: " + e, true);}}} finally {if (c != null) {c.close();}}// Break early if we've stopped loadingif (mStopped) {clearSBgDataStructures();return false;}if (itemsToRemove.size() > 0) {ContentProviderClient client = contentResolver.acquireContentProviderClient(LauncherSettings.Favorites.CONTENT_URI);// Remove dead itemsfor (long id : itemsToRemove) {if (DEBUG_LOADERS) {Log.d(TAG, "Removed id = " + id);}// Don't notify content observerstry {client.delete(LauncherSettings.Favorites.getContentUri(id, false),null, null);} catch (RemoteException e) {Log.w(TAG, "Could not remove id = " + id);}}}if (loadedOldDb) {long maxScreenId = 0;// If we're importing we use the old screen order.for (ItemInfo item: sBgItemsIdMap.values()) {long screenId = item.screenId;if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&!sBgWorkspaceScreens.contains(screenId)) {sBgWorkspaceScreens.add(screenId);if (screenId > maxScreenId) {maxScreenId = screenId;}}}Collections.sort(sBgWorkspaceScreens);LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);// Update the max item id after we load an old dblong maxItemId = 0;// If we're importing we use the old screen order.for (ItemInfo item: sBgItemsIdMap.values()) {maxItemId = Math.max(maxItemId, item.id);}LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);} else {TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);for (Integer i : orderedScreens.keySet()) {sBgWorkspaceScreens.add(orderedScreens.get(i));}// Remove any empty screensArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);for (ItemInfo item: sBgItemsIdMap.values()) {long screenId = item.screenId;if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&unusedScreens.contains(screenId)) {unusedScreens.remove(screenId);}}// If there are any empty screens remove them, and update.if (unusedScreens.size() != 0) {sBgWorkspaceScreens.removeAll(unusedScreens);updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);}}if (DEBUG_LOADERS) {Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");Log.d(TAG, "workspace layout: ");int nScreens = occupied.size();for (int y = 0; y < countY; y++) {String line = "";Iterator<Long> iter = occupied.keySet().iterator();while (iter.hasNext()) {long screenId = iter.next();if (screenId > 0) {line += " | ";}for (int x = 0; x < countX; x++) {line += ((occupied.get(screenId)[x][y] != null) ? "#" : ".");}}Log.d(TAG, "[ " + line + " ]");}}}return loadedOldDb;}
这个方法也太长了,挑重点的看吧:final Cursor c = contentResolver.query(contentUri, null, null, null, null);查询数据库
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);final int appWidgetProviderIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_PROVIDER);final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
通过Cursor 拿到应用的信息
while (!mStopped && c.moveToNext()) {AtomicBoolean deleteOnItemOverlap = new AtomicBoolean(false);try {int itemType = c.getInt(itemTypeIndex);switch (itemType) {case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:id = c.getLong(idIndex);intentDescription = c.getString(intentIndex);try {intent = Intent.parseUri(intentDescription, 0);ComponentName cn = intent.getComponent();if (cn != null && !isValidPackageComponent(manager, cn)) {if (!mAppsCanBeOnRemoveableStorage) {// Log the invalid package, and remove it from the dbLauncher.addDumpLog(TAG, "Invalid package removed: " + cn, true);itemsToRemove.add(id);} else {// If apps can be on external storage, then we just// leave them for the user to remove (maybe add// visual treatment to it)Launcher.addDumpLog(TAG, "Invalid package found: " + cn, true);}continue;}} catch (URISyntaxException e) {Launcher.addDumpLog(TAG, "Invalid uri: " + intentDescription, true);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);// App shortcuts that used to be automatically added to Launcher// didn't always have the correct intent flags set, so do that// hereif (intent.getAction() != null &&intent.getCategories() != null &&intent.getAction().equals(Intent.ACTION_MAIN) &&intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);}}if (info != null) {info.id = id;info.intent = intent;container = c.getInt(containerIndex);info.container = container;info.screenId = c.getInt(screenIndex);info.cellX = c.getInt(cellXIndex);info.cellY = c.getInt(cellYIndex);info.spanX = 1;info.spanY = 1;// Skip loading items that are out of boundsif (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {if (checkItemDimensions(info)) {Launcher.addDumpLog(TAG, "Skipped loading out of bounds shortcut: "+ info + ", " + grid.numColumns + "x" + grid.numRows, true);continue;}}// check & update map of what's occupieddeleteOnItemOverlap.set(false);if (!checkItemPlacement(occupied, info, deleteOnItemOverlap)) {if (deleteOnItemOverlap.get()) {itemsToRemove.add(id);}break;}switch (container) {case LauncherSettings.Favorites.CONTAINER_DESKTOP:case LauncherSettings.Favorites.CONTAINER_HOTSEAT:sBgWorkspaceItems.add(info);break;default:// Item is in a user folderFolderInfo folderInfo =findOrMakeFolder(sBgFolders, container);folderInfo.add(info);break;}sBgItemsIdMap.put(info.id, info);// now that we've loaded everthing re-save it with the// icon in case it disappears somehow.queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);} else {throw new RuntimeException("Unexpected null ShortcutInfo");}break;case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:id = c.getLong(idIndex);FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);folderInfo.title = c.getString(titleIndex);folderInfo.id = id;container = c.getInt(containerIndex);folderInfo.container = container;folderInfo.screenId = c.getInt(screenIndex);folderInfo.cellX = c.getInt(cellXIndex);folderInfo.cellY = c.getInt(cellYIndex);folderInfo.spanX = 1;folderInfo.spanY = 1;// Skip loading items that are out of boundsif (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {if (checkItemDimensions(folderInfo)) {Log.d(TAG, "Skipped loading out of bounds folder");continue;}}// check & update map of what's occupieddeleteOnItemOverlap.set(false);if (!checkItemPlacement(occupied, folderInfo,deleteOnItemOverlap)) {if (deleteOnItemOverlap.get()) {itemsToRemove.add(id);}break;}switch (container) {case LauncherSettings.Favorites.CONTAINER_DESKTOP:case LauncherSettings.Favorites.CONTAINER_HOTSEAT:sBgWorkspaceItems.add(folderInfo);break;}sBgItemsIdMap.put(folderInfo.id, folderInfo);sBgFolders.put(folderInfo.id, folderInfo);break;case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:// Read all Launcher-specific widget detailsint appWidgetId = c.getInt(appWidgetIdIndex);String savedProvider = c.getString(appWidgetProviderIndex);id = c.getLong(idIndex);final AppWidgetProviderInfo provider =widgets.getAppWidgetInfo(appWidgetId);if (!isSafeMode && (provider == null || provider.provider == null ||provider.provider.getPackageName() == null)) {String log = "Deleting widget that isn't installed anymore: id="+ id + " appWidgetId=" + appWidgetId;Log.e(TAG, log);Launcher.addDumpLog(TAG, log, false);itemsToRemove.add(id);} else {appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,provider.provider);appWidgetInfo.id = id;appWidgetInfo.screenId = c.getInt(screenIndex);appWidgetInfo.cellX = c.getInt(cellXIndex);appWidgetInfo.cellY = c.getInt(cellYIndex);appWidgetInfo.spanX = c.getInt(spanXIndex);appWidgetInfo.spanY = c.getInt(spanYIndex);int[] minSpan = Launcher.getMinSpanForWidget(context, provider);appWidgetInfo.minSpanX = minSpan[0];appWidgetInfo.minSpanY = minSpan[1];container = c.getInt(containerIndex);if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {Log.e(TAG, "Widget found where container != " +"CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");continue;}appWidgetInfo.container = c.getInt(containerIndex);// Skip loading items that are out of boundsif (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {if (checkItemDimensions(appWidgetInfo)) {Log.d(TAG, "Skipped loading out of bounds app widget");continue;}}// check & update map of what's occupieddeleteOnItemOverlap.set(false);if (!checkItemPlacement(occupied, appWidgetInfo,deleteOnItemOverlap)) {if (deleteOnItemOverlap.get()) {itemsToRemove.add(id);}break;}String providerName = provider.provider.flattenToString();if (!providerName.equals(savedProvider)) {ContentValues values = new ContentValues();values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,providerName);String where = BaseColumns._ID + "= ?";String[] args = {Integer.toString(c.getInt(idIndex))};contentResolver.update(contentUri, values, where, args);}sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);sBgAppWidgets.add(appWidgetInfo);}break;}} catch (Exception e) {Launcher.addDumpLog(TAG, "Desktop items loading interrupted: " + e, true);}}
通过拿到的应用信息,然后判断itemType分别给是加载快捷方式还是具体的应用,是桌面还是hotseat上的数据,
将信息塞给getShortcutInfo(manager, intent, context, c, iconIndex, titleIndex, mLabelCache);生成ShortcutInfo,在判断info!= null将数据分类到哪一个container,哪一个文件夹,
继续回到loadAndBindWorkspace()方法:查询分类完成之后就是绑定信息:
private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {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>();ArrayList<Long> orderedScreenIds = new ArrayList<Long>();synchronized (sBgLock) {workspaceItems.addAll(sBgWorkspaceItems);appWidgets.addAll(sBgAppWidgets);folders.putAll(sBgFolders);itemsIdMap.putAll(sBgItemsIdMap);orderedScreenIds.addAll(sBgWorkspaceScreens);}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 itemsfilterCurrentWorkspaceItems(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 itemsr = new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.startBinding();}}};runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);bindWorkspaceScreens(oldCallbacks, orderedScreenIds);// Load items on the current pagebindWorkspaceItems(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, MAIN_THREAD_BINDING_RUNNABLE);}// 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 itemsr = new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.finishBindingItems(isUpgradePath);}// 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, MAIN_THREAD_BINDING_RUNNABLE);}}
看到里面这么多集合是干什么用的;就是将不同的分类放到不同的集合在加入不同信息,维护六个集合,r = new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.startBinding();}}};runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
```
注册监听,开始绑定了:进去看看
public void startBinding() {
// If we’re starting binding all over again, clear any bind calls we’d postponed in
// the past (see waitUntilResume) – we don’t need them since we’re starting binding
// from scratch again
mBindOnResumeCallbacks.clear();
// Clear the workspace because it's going to be reboundmWorkspace.clearDropTargets();mWorkspace.removeAllWorkspaceScreens();mWidgetsToAdvance.clear();if (mHotseat != null) {mHotseat.resetLayout();}
}就是对view的清空,
然后 bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,currentFolders, null);加载当前页的item;跟到这个方法里面去就看到
if (callbacks != null) {callbacks.bindItems(workspaceItems, start, start+chunkSize, false);}
就看到了bindItems,就到Launcher里面回调,
public void bindAppsAdded(final ArrayList newScreens,
final ArrayList addNotAnimated,
final ArrayList addAnimated,
final ArrayList addedApps) {
Runnable r = new Runnable() {
public void run() {
bindAppsAdded(newScreens, addNotAnimated, addAnimated, addedApps);
}
};
if (waitUntilResume(r)) {
return;
}
// Add the new screensbindAddScreens(newScreens);// We add the items without animation on non-visible pages, and with// animations on the new page (which we will try and snap to).if (!addNotAnimated.isEmpty()) {bindItems(addNotAnimated, 0,addNotAnimated.size(), false);}if (!addAnimated.isEmpty()) {bindItems(addAnimated, 0,addAnimated.size(), true);}// Remove the extra empty screenmWorkspace.removeExtraEmptyScreen();if (!AppsCustomizePagedView.DISABLE_ALL_APPS &&addedApps != null && mAppsCustomizeContent != null) {mAppsCustomizeContent.addApps(addedApps);}
}
看到bindItems了那就是要绑定数据了最终会调用workspace的addInScreenFromBind()
void addInScreenFromBind(View child, long container, long screenId, int x, int y,int spanX, int spanY) {addInScreen(child, container, screenId, x, y, spanX, spanY, false, true);}
就加载到屏幕上了;“`
r = new Runnable() {public void run() {Callbacks callbacks = tryGetCallbacks(oldCallbacks);if (callbacks != null) {callbacks.finishBindingItems(isUpgradePath);}// 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, MAIN_THREAD_BINDING_RUNNABLE);}
finishBindingItems注册一个callback,Launcher实现,就是加载数据完成之后做的操作!
Launcher app数据加载流程相关推荐
- android平台gallery2应用分析,Android5.1图库Gallery2代码分析数据加载流程
图片数据加载流程. Gallery---->GalleryActivity------>AlbumSetPage------->AlbumPage--------->Photo ...
- android Q launcher 数据加载流程
时间:2020/08/24 之前公司不允许csdn,笔记写在其它地方.最近整理过来 下一篇:launcher数据加载(二) 前言 androidQ和androidP上Launcher结构有很大区别. ...
- 【深度学习-数据加载优化-训练速度提升一倍】
1,介绍 数据加载 深度学习的训练,简单的说就是将数据切分成batch,丢入模型中,并计算loss训练.其中比较重要的一环是数据打batch部分(数据加载部分). 训练时间优化: 深度学习训练往往需要 ...
- PyTorch1.12 亮点一览 | DataPipe + TorchArrow 新的数据加载与处理范式
目录 前言 现有的 Dataset 和 DataLoader 及其存在的问题 新的数据加载方式:DataPipe 与 DataLoader2 结构化数据处理新范式:TorchArrow 总结 参考链接 ...
- Launcher启动流程加载流程学习
声明: 图片本来是有的 涉及到有些代码不能示人没有贴上,不过仅文字说也足够了,请广大老爷们自行下载源码参看流程分析阅读. 目录 一.认识Launcher: 1 1.功能 1 2.样式 2 3.And ...
- Android----Allapps加载流程详解【AndroidICS4.0——Launcher系列五】
工作需要总结,这样就能保证地基牢固,就能爬得更高: ----2013-01-07题记 转载请标明出处:http://blog.csdn.net/wdaming1986/article/details/ ...
- android Launcher——数据加载与变更
在前面我的blog中,我已经说过了,Launcher所有的桌面项数据是存储在launcher.db/favorites表中 在Launcher启动时loadeworkspace函数中会从数据库中查询所 ...
- 总结Vue中index.html、main.js、App.vue、index.js之间关系以及Vue项目加载流程
总结Vue中index.html.main.js.App.vue.index.js之间关系以及Vue项目加载流程 文章目录 总结Vue中index.html.main.js.App.vue.index ...
- Launcher3 桌面加载流程分析
Launcher3 桌面加载流程分析 主入口Launcher 首先来看Launcher.java的onCreate方法,里面代码很多,只看主流程部分: @Override protected void ...
最新文章
- 无人驾驶汽车系统入门:基于深度学习的实时激光雷达点云目标检测及ROS实现...
- JS 使用html2canvas实现截图功能的问题记录和解决方案
- python映射类型-Python中字典映射类型的学习教程
- 做系统ghost步骤图解_Ghost 博客搭建超全指南
- 在BAdI definition PRODUCT_R3_ADAPTER的implementation里获得download type
- Matlab矩阵、元胞数组的合并拼接
- RPC 远程过程调用协议
- php文本文件操作,文本文件操作的php类
- cli版的php.ini路径,CLI 执行 PHP 时自订 php.ini 设定档
- docker教程_2 docker常见命令
- STL之pair及其非成员函数make_pair()
- 计算机软件资产代码,事业单位六大类固定资产代码.xls
- 开源的项目管理软件——OpenProj
- 关于卸载迈克菲全方位实时保护的时候出现已取消网页导航的一下观点
- 两个小故事告诉你静下来的力量
- 老子智慧 之 知人者智 自知者明 [明智]
- 程序员技术路线图(经典)
- 【MATLAB】理解采样频率和信号频率的关系
- 计算机word图标不显示,word图标不显示怎么办 设置图标显示的具体方法
- Scilab的初步介绍