Launcher3的数据加载过程涉及到了两个主要的类LauncherProvider和LauncherModel。
LauncherProvider
LauncherProvider继承自ContentProvider类,内部基于数据库存储实现了ContentProvider的CRUD接口,这个类主要用于更新数据库的数据。LauncherProvider内部维护了两张数据表,favorites(用于存储workspace上的内容信息)和workspaceScreens(用于存储screen的排序和页数的信息)。
favorites表的创建语句:
db.execSQL("CREATE TABLE favorites (" +
"_id INTEGER PRIMARY KEY," + // id
"title TEXT," + // 名字
"intent TEXT," + // intent的字符串描述
"container INTEGER," + // 容器类型,desktop或者hotseat
"screen INTEGER," + // 所在的屏幕号
"cellX INTEGER," + // item左上方所在的格子x位置
"cellY INTEGER," + // item左上方所在的格子y位置
"spanX INTEGER," + // item横向占用的格子数
"spanY INTEGER," + // item纵向占用的格子数
"itemType INTEGER," + // item的类型,app,widget,folder
"appWidgetId INTEGER NOT NULL DEFAULT -1," + // widget的id
"isShortcut INTEGER," + // 是否是快捷方式
"iconType INTEGER," + ...
"iconPackage TEXT," +
"iconResource TEXT," +
"icon BLOB," +
"uri TEXT," +
"displayMode INTEGER," +
"appWidgetProvider TEXT," +
"modified INTEGER NOT NULL DEFAULT 0" +
");");
favorites用于存储workspace上的内容信息,它存储了内容的类型和所在的位置等信息。
workspaceScreens表的创建语句:
db.execSQL("CREATE TABLE " + TABLE_WORKSPACE_SCREENS + " (" +
LauncherSettings.WorkspaceScreens._ID + " INTEGER," +
LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER," +
LauncherSettings.ChangeLogColumns.MODIFIED + " INTEGER NOT NULL DEFAULT 0" +
");");
当从数据库获取了数据后,需要一个数据对象在内存中维护这些信息。Launcher3中定义了一系列的数据类,如下图所示:
AppInfo:代表所有应用界面的一个app
FolderInfo:代表一个文件夹
LauncherAppWidgetInfo:代表一个widget
ShortcutInfo:代表workspace和folder里的app
LauncherModel用于维护内存中的数据,通过ContentResolver来更新LauncherProvider的数据,即数据库的数据。LauncherModel内部有个继承自Runnable的LoaderTask引用,Launcher的数据加载就是在这个类中执行,当调用LauncherModel.startLoader()时就会执行LoaderTask.run()方法,开始数据的加载工作。
LauncherModel内部维护了几个列表,用于存储从数据库获取的数据:
// sBgItemsIdMap存储了所有的ItemInfos (shortcuts, folders, and widgets),以item的id作为key
static final HashMap sBgItemsIdMap = new HashMap();
// sBgWorkspaceItems将作为参数传递给bindItems, 存储了在workspace上显示的所有app和folder信息
static final ArrayList sBgWorkspaceItems = new ArrayList();
// sBgAppWidgets存储了workspace上的widget信息,作为参数传递给bindAppWidget()
static final ArrayList sBgAppWidgets = new ArrayList();
// sBgFolders存储了workspace上的folder信息,作为参数传递给bindFolders()
static final HashMap sBgFolders = new HashMap();
// sBgDbIconCache存储了在数据库维护的item的图片
static final HashMap
LauncherModel的结构图:
Workspace数据的加载过程
Launcher3的数据加载分为两部分,一个是Workspace页面的数据:Launcher最主要的界面,用户可自由编辑内容(widget,app, folder,screen),第二部分是所有应用界面。下面我们先来看Workspace的数据加载过程,通过在LoaderTask.run()方法里调用loadAndBindWorkspace()开始整个过程,下面是具体代码:
/** Returns whether this is an upgrade path */
private boolean loadAndBindWorkspace() {
mIsLoadingAndBindingWorkspace = true;
boolean isUpgradePath = false;
if (!mWorkspaceLoaded) {
// Load the workspace
isUpgradePath = loadWorkspace();
synchronized (LoaderTask.this) {
if (mStopped) {
return isUpgradePath;
}
mWorkspaceLoaded = true;
}
}
// Bind the workspace
bindWorkspace(-1, isUpgradePath);
return isUpgradePath;
}
整个过程分为两步,load和bind,完成第一步后会判断任务是否终止,如果是则不继续下一步。代码中用到了synchronized块,因为这个过程涉及到多线程处理。我们先看loadWorkspace(),也就是workspace的数据加载过程,以下是大体流程:
1. 如果数据库为空,先加载xml的数据
加载时,首先会判断数据库的类容是否为空,如果是,会先从一个xml文件中加载workspace的类容,Launcher3的默认xml文件路径为res/xml/default_workspace.xml,里面定义了默认的app和widget信息,这个过程由loadFavorates()实现。
默认xml的内容如下:
loadFavorates()代码如下:
/**
* Loads the default set of favorite packages from an xml file.
*
* @param db The database to write the values into
* @param filterContainerId The specific container id of items to load
*/
private int loadFavorites(SQLiteDatabase db, int workspaceResourceId) {
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ContentValues values = new ContentValues();
PackageManager packageManager = mContext.getPackageManager();
int i = 0;
try {
XmlResourceParser parser = mContext.getResources().getXml(workspaceResourceId);
AttributeSet attrs = Xml.asAttributeSet(parser);
beginDocument(parser, TAG_FAVORITES);
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
boolean added = false;
final String name = parser.getName();
......
// apps,widgets和folder都是Favorate类型
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite);
// 判断元素是在workspace还是hotseat
long container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
if (a.hasValue(R.styleable.Favorite_container)) {
container = Long.valueOf(a.getString(R.styleable.Favorite_container));
}
......
if (TAG_FAVORITE.equals(name)) {
// 添加默认shortcut到数据库
long id = addAppShortcut(db, values, a, packageManager, intent);
added = id >= 0;
} else if (TAG_APPWIDGET.equals(name)) {
// 添加默认widget到数据库
added = addAppWidget(parser, attrs, type, db, values, a, packageManager);
} else if (TAG_FOLDER.equals(name)) {
// 添加folder到数据库
added = addAppFolder();
}
if (added) i++;
a.recycle();
}
} catch (XmlPullParserException e) {
Log.w(TAG, "Got exception parsing favorites.", e);
} catch (IOException e) {
Log.w(TAG, "Got exception parsing favorites.", e);
} catch (RuntimeException e) {
Log.w(TAG, "Got exception parsing favorites.", e);
}
// Update the max item id after we have loaded the database
if (mMaxItemId == -1) {
mMaxItemId = initializeMaxItemId(db);
}
return i;
}
addAppShortcut,addAppWIdget,addAppFolder是把xml获取到的数据insert到数据库中,下面是addAppShortcut的代码:
private long addAppShortcut(SQLiteDatabase db, ContentValues values, TypedArray a,
PackageManager packageManager, Intent intent) {
long id = -1;
ActivityInfo info;
String packageName = a.getString(R.styleable.Favorite_packageName);
String className = a.getString(R.styleable.Favorite_className);
try {
ComponentName cn;
try {
cn = new ComponentName(packageName, className);
info = packageManager.getActivityInfo(cn, 0);
} catch (PackageManager.NameNotFoundException nnfe) {
String[] packages = packageManager.currentToCanonicalPackageNames(
new String[] { packageName });
cn = new ComponentName(packages[0], className);
info = packageManager.getActivityInfo(cn, 0);
}
id = generateNewItemId();
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
values.put(LauncherSettings.Favorites.INTENT, intent.toUri(0));
values.put(LauncherSettings.Favorites.TITLE, info.loadLabel(packageManager).toString());
values.put(LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
values.put(LauncherSettings.Favorites.SPANX, 1);
values.put(LauncherSettings.Favorites.SPANY, 1);
values.put(LauncherSettings.Favorites._ID, generateNewItemId());
// 将数据insert到数据库
if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) {
return -1;
}
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Unable to add favorite: " + packageName +
"/" + className, e);
}
return id;
}
addAppWidget的代码:
private boolean addAppWidget(SQLiteDatabase db, ContentValues values, ComponentName cn,
int spanX, int spanY, Bundle extras) {
boolean allocatedAppWidgets = false;
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
try {
// 如果应用中需要嵌入widget(比如Launcher应用),需要有一个AppWidgetHost实例,
// AppWidgetHost为每一个嵌入的widget分配一个id进行管理,AppWidgetHost为应用
// 提供了与AppWidget service的交互,AppWidgetManager可以通过此id获取provider信息
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
values.put(LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET);
values.put(LauncherSettings.Favorites.SPANX, spanX);
values.put(LauncherSettings.Favorites.SPANY, spanY);
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, cn.flattenToString());
values.put(LauncherSettings.Favorites._ID, generateNewItemId());
dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values);
allocatedAppWidgets = true;
// 每个添加到应用的widget都需要调用该方法
appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn);
// Send a broadcast to configure the widget
if (extras != null && !extras.isEmpty()) {
Intent intent = new Intent(ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE);
intent.setComponent(cn);
intent.putExtras(extras);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
mContext.sendBroadcast(intent);
}
} catch (RuntimeException ex) {
Log.e(TAG, "Problem allocating appWidgetId", ex);
}
return allocatedAppWidgets;
}
2. 将数据库的数据加载到内存
/** Returns whether this is an upgradge path */
private boolean loadWorkspace() {
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();
synchronized (sBgLock) {
// 清空之前的内存数据(sBgWorkspaceItems,sBgAppWidgets等)
clearSBgDataStructures();
// 存储无效数据的id,在后面统一从数据库中删掉
final ArrayList itemsToRemove = new ArrayList();
// 查询ContentProvider,返回favorites表的结果集
final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;
final Cursor c = contentResolver.query(contentUri, null, null, null, null);
// 用于判断格子是否已经被占用
final HashMap occupied = new HashMap();
try {
// 获取数据库每一列的索引值,通过cursor.getDataType(columnIndex)可获取相应列的值
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);
// 存储app信息的对象引用
ShortcutInfo info;
String intentDescription;
// 存储widget信息的对象引用
LauncherAppWidgetInfo appWidgetInfo;
int container;
long id;
Intent intent;
// 遍历结果集,如果当前是stop状态,则停止遍历
while (!mStopped && c.moveToNext()) {
// 标志格子是否已被占
AtomicBoolean deleteOnItemOverlap = new AtomicBoolean(false);
try {
// 获取item的类型,app,widget,folder
int itemType = c.getInt(itemTypeIndex);
switch (itemType) {
// workspace上的app属于ITEM_TYPE_APPLICATION
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)) {
// 如果应用程序包名无效,则添加到移除列表
itemsToRemove.add(id);
continue;
}
} catch (URISyntaxException e) {
Launcher.addDumpLog(TAG, "Invalid uri: " + intentDescription, true);
continue;
}
if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
// app类型的shortcut,生成一个ShortcutInfo对象,对info的icon和title赋值
info = getShortcutInfo(manager, intent, context, c, iconIndex,
titleIndex, mLabelCache);
} else {
// 不是app类型的shortcut
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
// here
if (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);
}
}
// 对info的其他信息赋值
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;
// 跳过超出屏幕范围的item
if (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 occupied
deleteOnItemOverlap.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:
// 如果item是在workspace或者hotseat
sBgWorkspaceItems.add(info);
break;
default:
// 如果container是folder,则添加到相应的folder中
FolderInfo folderInfo =
findOrMakeFolder(sBgFolders, container);
folderInfo.add(info);
break;
}
// 将item添加到列表
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);
// 从sBgFolders获取一个key为id的FolderInfo对象,如果找不到,
// 则new一个FolderInfo,并以此id为key添加到sBgFolders中
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;
// 跳过超出边界的item
if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
if (checkItemDimensions(folderInfo)) {
Log.d(TAG, "Skipped loading out of bounds folder");
continue;
}
}
// 移除格子被占的item
deleteOnItemOverlap.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 details
int appWidgetId = c.getInt(appWidgetIdIndex);
String savedProvider = c.getString(appWidgetProviderIndex);
id = c.getLong(idIndex);
// widgets是AppWidgetManager的对象引用
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);
// 根据widget内部的width,height和padding计算出widget在launcher中所占的格子
int[] minSpan = Launcher.getMinSpanForWidget(context, provider);
appWidgetInfo.minSpanX = minSpan[0];
appWidgetInfo.minSpanY = minSpan[1];
container = c.getInt(containerIndex);
// widget的container只能是workspace或者hotseat.
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 bounds
if (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 occupied
deleteOnItemOverlap.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 {
// cursor用完后需要关闭
if (c != null) {
c.close();
}
}
// Break early if we've stopped loading
if (mStopped) {
clearSBgDataStructures();
return false;
}
// 在ContentProvider中删除无效的items
if (itemsToRemove.size() > 0) {
ContentProviderClient client = contentResolver.acquireContentProviderClient(
LauncherSettings.Favorites.CONTENT_URI);
// Remove dead items
for (long id : itemsToRemove) {
if (DEBUG_LOADERS) {
Log.d(TAG, "Removed id = " + id);
}
// Don't notify content observers
try {
client.delete(LauncherSettings.Favorites.getContentUri(id, false),
null, null);
} catch (RemoteException e) {
Log.w(TAG, "Could not remove id = " + id);
}
}
}
if (loadedOldDb) {
// 加载screen数据,获取最大屏幕id
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 db
long 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 orderedScreens = loadWorkspaceScreensDb(mContext);
for (Integer i : orderedScreens.keySet()) {
sBgWorkspaceScreens.add(orderedScreens.get(i));
}
// Remove any empty screens
ArrayList unusedScreens = new ArrayList(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);
}
}
}
return loadedOldDb;
}
经过以上步骤,数据库中的数据就存到了LauncherModel相应的数据列表里(sBgItemsIdMap,sBgWorkspaceItemsm,sBgAppWidgets,sBgFolders,sBgWorkspaceScreens),下一步就是将数据绑定到Launcher界面的过程了。