天天看點

Android Launcher3(一) -- 啟動過程

本文将以代碼走讀的形式講解Launcher3的啟動過程,主要包括資料的加載,到界面的生成過程

1、入口Launcher.java

 @Override

 protected void onCreate(Bundle savedInstanceState) {

  ...

  // 1)加載布局

  setContentView(R.layout.launcher);

  setupViews();

  registerContentObservers();

  ...

  // 2)LauncherModel開始加載資料

<pre class="html" name="code">  if (!mRestoring) {

   if (sPausedFromUserAction) {

    mModel.startLoader(true, -1);

   } else {

    mModel.startLoader(true, mWorkspace.getCurrentPage());

   }

  }

  ...

 }

2、資料加載LauncherModel,LauncherModel相當于Launcher的Controller

 public void startLoader(boolean isLaunching, int synchronousBindPage) {

  synchronized (mLock) {

   ...

   if (mCallbacks != null && mCallbacks.get() != null) {

    ...

    // 啟動mLoaderTask來加載資料,LoaderTask是一個實作了Runnable方法的内部類

    mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching);

    if (synchronousBindPage > -1 && mAllAppsLoaded && mWorkspaceLoaded) {

     mLoaderTask.runBindSynchronousPage(synchronousBindPage);

    } else {

     sWorkerThread.setPriority(Thread.NORM_PRIORITY);

     sWorker.post(mLoaderTask);

    }

   }

  }

 }

LoaderTask的run()方法如下

<pre class="html" name="code"> public void run() {

  keep_running: {

   synchronized (mLock) {

   // 1)加載workspace資料并綁定view   

   isUpgrade = loadAndBindWorkspace();

   ...

   // 2)加載allApp資料并綁定view

   loadAndBindAllApps();

   ...

  }

  ... 

 }

2.1 先看workspace的加載

 private boolean loadAndBindWorkspace() {

  ...

  if (!mWorkspaceLoaded) {

   // 1)加載workspace中的資料

   isUpgradePath = loadWorkspace();

   ...

  }

  // 2)加載view

  bindWorkspace(-1, isUpgradePath);

  return isUpgradePath;

 }

 private boolean loadWorkspace() {

  // 1)確定預設workspace的資料得到加載

  LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);

  synchronized (sBgLock) {

   final ArrayList<Long> itemsToRemove = new ArrayList<Long>();

       final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;

   // 2)資料查詢

       final Cursor c = contentResolver.query(contentUri, null, null, null, null);

   // 3)解析Cursor

   while (!mStopped && c.moveToNext()) {

          ...

   }

   ...

   // 4)更新螢幕次序

   updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);

   ...

  }

 }

 // 在主線程中将資料加載到實際的View中

 private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {

  ...

  // 1)資料預處理

  filterCurrentWorkspaceItems(currentScreen, workspaceItems, currentWorkspaceItems, otherWorkspaceItems);

     filterCurrentAppWidgets(currentScreen, appWidgets, currentAppWidgets, otherAppWidgets);

     filterCurrentFolders(currentScreen, itemsIdMap, folders, currentFolders, otherFolders);

     sortWorkspaceItemsSpatially(currentWorkspaceItems);

     sortWorkspaceItemsSpatially(otherWorkspaceItems);

  // 2)回調,對應 Launcher.java 中的 startBinding()

  ...

        callbacks.startBinding();

  // 3)添加界面控件,完成Workspace界面的繪制

  bindWorkspaceScreens(oldCallbacks, orderedScreenIds);

  bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, currentFolders, null);

  bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,

        (isLoadingSynchronously ? mDeferredBindRunnables : null));

  // 4)加載完成,回調Lancher.finishBindingItems(isUpgradePath)

  callbacks.finishBindingItems(isUpgradePath);

  ...

 }

 private void bindWorkspaceItems(final Callbacks oldCallbacks, final ArrayList<ItemInfoBean> workspaceItems,

      final ArrayList<LauncherAppWidgetInfoBean> appWidgets, final HashMap<Long, FolderInfoBean> folders,

      ArrayList<Runnable> deferredBindRunnables) {

  int N = workspaceItems.size();

  // 1)ShortCut 回調Launcher中的bindItems(...)

     for (int i = 0; i < N; i += ITEMS_CHUNK) {

   callbacks.bindItems(workspaceItems, start, start + chunkSize, false);

  }

  // 2)Folders

  callbacks.bindFolders(folders);

  // 3)Widget

  for (int i = 0; i < N; i++) {

   callbacks.bindAppWidget(widget);

  }

 }

 // 再看Launcher中的bindItems()

 public void bindItems(final ArrayList<ItemInfoBean> shortcuts, final int start, final int end,

     final boolean forceAnimateIcons) {

  ...

  for (int i = start; i < end; i++) {

     final ItemInfoBean item = shortcuts.get(i);

     switch (item.itemType) {

     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:

     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:

   // 在Workspace.java的addInScreenFromBind(...)方法中真正添加各個View

   // layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)

       workspace.addInScreenFromBind(shortcut, item.container, item.screenId, item.cellX, item.cellY, 1, 1);

  ...

  }

 }

2.2 AllApps的加載

 private void loadAndBindAllApps() {

  ...

  loadAllApps();

 )

 private void loadAllApps() {

  // 1)查詢所有App的資訊

  List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);

  // 2)根據名稱排序

  Collections.sort(apps, new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));

  // 3)添加圖示資訊

  for (int i = 0; i < apps.size(); i++) {

       ResolveInfo app = apps.get(i);

   mBgAllAppsList.add(new AppInfoBean(packageManager, app, mIconCache, mLabelCache));

  }

  // 4)回調Launcher.bindAllApplications(ArrayList<AppInfoBean> beans)

  callbacks.bindAllApplications(added);

  ...

 }

 因為進入Launcher先隻是顯示workspace界面,是以allapp界面暫時不顯示,view不會被添加進去,隻是準備好所有App的資料資訊,至此我們能夠看到加載了ShortCut,Folder,Widget的Launcher界面