通过调用bindScreens(),主界面完成了页面的加载,接下来就要开始加载各页面内容了。为了提高用户体验,会先加载当前页面的内容,再加载其他页面的内容。在workspace中调用bindWorkspaceItems()完成页面内容的加载,具体代码如下:
// oldCallbacks: 一个Callback引用
// workspaceItems: 页面的apps和folder
// appWidgets: 页面的widgets
// folders: 文件夹信息
private void bindWorkspaceItems(final Callbacks oldCallbacks,
final ArrayList workspaceItems,
final ArrayList appWidgets,
final HashMap folders,
ArrayList deferredBindRunnables) {
// 这里为null,即postOnMainThread为false
final boolean postOnMainThread = (deferredBindRunnables != null);
// Bind the workspace items
int N = workspaceItems.size();
// 为了提高用户体验,分成几块进行加载,ITEMS_CHUNK的默认值为6
for (int i = 0; i < N; i += ITEMS_CHUNK) {
final int start = i;
final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);
final Runnable r = new Runnable() {
@Override
public void run() {
Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindItems(workspaceItems, start, start+chunkSize,
false);
}
}
};
if (postOnMainThread) {
deferredBindRunnables.add(r);
} else {
runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
}
}
// Bind the folders
if (!folders.isEmpty()) {
final Runnable r = new Runnable() {
public void run() {
Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindFolders(folders);
}
}
};
if (postOnMainThread) {
deferredBindRunnables.add(r);
} else {
runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
}
}
// Bind the widgets, one at a time
N = appWidgets.size();
for (int i = 0; i < N; i++) {
final LauncherAppWidgetInfo widget = appWidgets.get(i);
final Runnable r = new Runnable() {
public void run() {
Callbacks callbacks = tryGetCallbacks(oldCallbacks);
if (callbacks != null) {
callbacks.bindAppWidget(widget);
}
}
};
if (postOnMainThread) {
deferredBindRunnables.add(r);
} else {
runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
}
}
}
可以看出,类容的加载过程可以分为以下三步骤:
接下来我们通过这几个回调方法的具体实现来看看这三个步骤完成的操作,Launcher类完成了上面三个回调方法的具体实现,我们从bindItems()方法开始分析,代码如下:
/**
* Bind the items start-end from the list.
*
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindItems(final ArrayList shortcuts, final int start, final int end,
final boolean forceAnimateIcons) {
// Get the list of added shortcuts and intersect them with the set of shortcuts here
Workspace workspace = mWorkspace;
long newShortcutsScreenId = -1;
for (int i = start; i < end; i++) {
final ItemInfo item = shortcuts.get(i);
// Short circuit if we are loading dock items for a configuration which has no dock
if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
mHotseat == null) {
continue;
}
switch (item.itemType) {
// item为快捷方式
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
ShortcutInfo info = (ShortcutInfo) item;
// 根据info创建一个BubbleTextView(内容的视图组件),info中包含了icon和title信息
View shortcut = createShortcut(info);
// 所需的控件是否已被占用
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
CellLayout cl = mWorkspace.getScreenWithId(item.screenId);
if (cl != null && cl.isOccupied(item.cellX, item.cellY)) {
throw new RuntimeException("OCCUPIED");
}
}
// 将shortcut添加到相应的页面
workspace.addInScreenFromBind(shortcut, item.container, item.screenId, item.cellX,
item.cellY, 1, 1);
break;
// item为文件夹
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
// 创建一个文件夹控件
FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
(ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
(FolderInfo) item, mIconCache);
// 将newFolder添加到相应的页面
workspace.addInScreenFromBind(newFolder, item.container, item.screenId, item.cellX,
item.cellY, 1, 1);
break;
default:
throw new RuntimeException("Invalid Item Type");
}
}
workspace.requestLayout();
}
bindFolders()的代码如下:
/**
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindFolders(final HashMap folders) {
sFolders.clear();
sFolders.putAll(folders);
}
/**
* Add the views for a widget to the workspace.
*
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindAppWidget(final LauncherAppWidgetInfo item) {
final Workspace workspace = mWorkspace;
final int appWidgetId = item.appWidgetId;
final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
item.hostView.setTag(item);
item.onBindAppWidget(this);
workspace.addInScreen(item.hostView, item.container, item.screenId, item.cellX,
item.cellY, item.spanX, item.spanY, false);
addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);
workspace.requestLayout();
}