码迷,mamicode.com
首页 > 移动开发 > 详细

Android Launcher源码结构

时间:2015-08-18 13:51:49      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:

Launcher 是 Android手机开启后第一个运行的 应用程序,也叫Home,或者叫做手机桌面。
本文介绍的是4.1源码的launcher2 app. Android41\packages\apps\Launcher2
 
技术分享
 
 
首先找到主Activity,打开AndroidManifest.xml  入口是  com.android.launcher2.Launcher 这个类
Launcher 主界面包含 wallpaper墙纸,work_screen屏幕, 最底部的hotseat, 以及all apps.
 
onCreate方法里面 主要初始化一些对象,包括拖拽对象,hotSeat,  墙纸大小设置,
打开主布局文件launcher.xml
外层是一个Framelayout叠层 com.android.launcher2.DragLayer
com.android.launcher2.Workspace.java 为主要Home Screen
手机里面包含了多个屏的滑动,一共有5个
  1. <com.android.launcher2.Workspace  
  2.     android:id="@+id/workspace"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingLeft="@dimen/workspace_left_padding"  
  6.     android:paddingRight="@dimen/workspace_right_padding"  
  7.     android:paddingTop="@dimen/workspace_top_padding"  
  8.     android:paddingBottom="@dimen/workspace_bottom_padding"  
  9.     launcher:defaultScreen="2"  
  10.     launcher:cellCountX="@integer/cell_count_x"  
  11.     launcher:cellCountY="@integer/cell_count_y"  
  12.     launcher:pageSpacing="@dimen/workspace_page_spacing"  
  13.     launcher:scrollIndicatorPaddingLeft="@dimen/qsb_bar_height"  
  14.     launcher:scrollIndicatorPaddingRight="@dimen/button_bar_height">  
  15.   
  16.     <include android:id="@+id/cell1" layout="@layout/workspace_screen" />  
  17.     <include android:id="@+id/cell2" layout="@layout/workspace_screen" />  
  18.     <include android:id="@+id/cell3" layout="@layout/workspace_screen" />  
  19.     <include android:id="@+id/cell4" layout="@layout/workspace_screen" />  
  20.     <include android:id="@+id/cell5" layout="@layout/workspace_screen" />  
  21. </com.android.launcher2.Workspace>  


每一个屏叫做 com.android.launcher2.CellLayout.java
  1. <com.android.launcher2.CellLayout  
  2.     xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"  
  4.   
  5.     android:layout_width="wrap_content"  
  6.     android:layout_height="wrap_content"  
  7.     android:paddingLeft="@dimen/cell_layout_left_padding"  
  8.     android:paddingRight="@dimen/cell_layout_right_padding"  
  9.     android:paddingTop="@dimen/cell_layout_top_padding"  
  10.     android:paddingBottom="@dimen/cell_layout_bottom_padding"  
  11.     android:hapticFeedbackEnabled="false"  
  12.   
  13.     launcher:cellWidth="@dimen/workspace_cell_width"  
  14.     launcher:cellHeight="@dimen/workspace_cell_height"  
  15.     launcher:widthGap="@dimen/workspace_width_gap"  
  16.     launcher:heightGap="@dimen/workspace_height_gap"  
  17.     launcher:maxGap="@dimen/workspace_max_gap" />  


Workspace.java 是继承ViewGroup
CellLayout 也是继承ViewGroup
 
Workspace.java 对象在Launcher里面做了一些初始化。
首先在setupViews方法里面 获取了对象引用。还包含了shortcut添加与删除操作。
 
在Workspace.java中onTouchEvent方法中,监听了屏幕的滑动操作,比如长按,拖动app图标。
拖动用DragController.java类,处理拖动计算坐标。
 
 

Android Launcher源码加载APP流程

   分析Android Launcher源码中的一些重要类之间的关系,基本的加载流程。先来看一个类图

技术分享

 

  Launcher.java 是主Activity 在onCreate方法里面初始化了LauncherMode实例.

 

 

  1. LauncherApplication app = ((LauncherApplication)getApplication());  

  1. mModel = app.setLauncher(this);  

直接进入LauncherApplication.java的方法 

 

 

  1. LauncherModel setLauncher(Launcher launcher) {  
  2.     mModel.initialize(launcher);  
  3.     return mModel;  
  4. }  

这里的mModel就是LauncherModel类了,LauncherModel扮演者重要的角色,实际上是个广播,监控app的安装,改变,和卸载另外就是加载所有app信息

 

这里Launcher实现了Callbacks接口,直接加入到callbacks列表中,后面的很多功能都要靠它回调处理

 

  1. public void initialize(Callbacks callbacks) {  
  2.     synchronized (mLock) {  
  3.         mCallbacks = new WeakReference<Callbacks>(callbacks);  
  4.     }  
  5. }  


 

在Launcher.java  onCreate的代码中看下面的一段代码.

 

  1. if (!mRestoring) {  
  2.     if (sPausedFromUserAction) {  
  3.         // If the user leaves launcher, then we should just load items asynchronously when  
  4.         // they return.  
  5.         mModel.startLoader(true, -1);  
  6.     } else {  
  7.         // We only load the page synchronously if the user rotates (or triggers a  
  8.         // configuration change) while launcher is in the foreground  
  9.         mModel.startLoader(true, mWorkspace.getCurrentPage());  
  10.     }  
  11. }  

源码中注释也显示了2中情况,一种是当前用户的界面不是桌面可能是某个应用程序界面 这样我们通过后台异步加载。

 

另外一种情况是 刷新当前页面的app信息数据. 

现在定位到LauncherMode.java源码中startLoader方法 部分代码如下.

 

  1. if (synchronousBindPage > -1 && mAllAppsLoaded && mWorkspaceLoaded) {  
  2.     mLoaderTask.runBindSynchronousPage(synchronousBindPage);//同步加载当前页  
  3. else {  
  4.     sWorkerThread.setPriority(Thread.NORM_PRIORITY);  
  5.     sWorker.post(mLoaderTask);//异步加载  
  6. }  
和上面讲的一样,加载当前页面信息还是更新所有信息. synchronousBindPage就是当前用户滑动到第几个屏幕,一共是5个屏幕.

 

我们用到了LoaderTask这个类是一个Runnable实现.  这个地方用的是HandlerThread (这个类我以前没用过,一直是自己获取Looper再处理的技术分享 )

这个类就是具体载入appinfo,appwidget,  folder的信息了。

我们看看LoaderTask run方法实现. 注意 LoaderTask 是LauncherMode的内部类.  

 

  1. keep_running: {  
  2.     // Elevate priority when Home launches for the first time to avoid  
  3.     // starving at boot time. Staring at a blank home is not cool.  
  4.     synchronized (mLock) {  
  5.         if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +  
  6.                 (mIsLaunching ? "DEFAULT" : "BACKGROUND"));  
  7.         android.os.Process.setThreadPriority(mIsLaunching  
  8.                 ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);  
  9.     }  
  10.     if (loadWorkspaceFirst) {  
  11.         if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");  
  12.         loadAndBindWorkspace();//第一次载入  
  13.     } else {  
  14.         if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps");  
  15.         loadAndBindAllApps(); //更新数据  
  16.     }  
  17.   
  18.     if (mStopped) {  
  19.         break keep_running;  
  20.     }  
  21.   
  22.     // Whew! Hard work done.  Slow us down, and wait until the UI thread has  
  23.     // settled down.  
  24.     synchronized (mLock) {  
  25.         if (mIsLaunching) {  
  26.             if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");  
  27.             android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  28.         }  
  29.     }  
  30.     waitForIdle();  
  31.   
  32.     // second step  
  33.     if (loadWorkspaceFirst) {  
  34.         if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");  
  35.         loadAndBindAllApps();  
  36.     } else {  
  37.         if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace");  
  38.         loadAndBindWorkspace();  
  39.     }  
  40.   
  41.     // Restore the default thread priority after we are done loading items  
  42.     synchronized (mLock) {  
  43.         android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);  
  44.     }  
  45. }  

按照源码的注释 是第一次加载workspace , 第二次加载所有的app 信息,你会发现 loadAndBindAllApps方法和loadAndBindWorkspace 2次调用是倒着的。

 

我的理解就是  先执行加载workspace 再执行加载all apps.

我们定位到 loadAndBindWorkspace方法中,

 

 

  1. if (!mWorkspaceLoaded) {  
  2.              loadWorkspace();  
  3.              synchronized (LoaderTask.this) {  
  4.                  if (mStopped) {  
  5.                      return;  
  6.                  }  
  7.                  mWorkspaceLoaded = true;  
  8.              }  
  9.          }  

如果workspace还没加载就调用loadWorkspace方法. 定位到这个方法里面,一目了然发现 都是直接获取应用程序信息了包括widget.

 

直接调用了 PackageManager,AppWidgetManager,ContentResolver 获取信息.

读取信息保存后 我们需要与workspace汇合,这个地方是调用bindWorkspace

在这个方面里面我们会发现使用前面说的callbacks进行回调完整数据与View的绑定显示.

 

  1. /** 
  2.    * Binds all loaded data to actual views on the main thread. 
  3.    */  
  4.   private void bindWorkspace(int synchronizeBindPage) {  
  5.       final long t = SystemClock.uptimeMillis();  
  6.       Runnable r;  
  7.   
  8.       // Don‘t use these two variables in any of the callback runnables.  
  9.       // Otherwise we hold a reference to them.  
  10.       final Callbacks oldCallbacks = mCallbacks.get();  
  11.       if (oldCallbacks == null) {  
  12.           // This launcher has exited and nobody bothered to tell us.  Just bail.  
  13.           Log.w(TAG, "LoaderTask running with no launcher");  
  14.           return;  
  15.       }  
  16.   
  17.       final boolean isLoadingSynchronously = (synchronizeBindPage > -1);  
  18.       final int currentScreen = isLoadingSynchronously ? synchronizeBindPage :  
  19.           oldCallbacks.getCurrentWorkspaceScreen();  
  20.   
  21.       // Load all the items that are on the current page first (and in the process, unbind  
  22.       // all the existing workspace items before we call startBinding() below.  
  23.       unbindWorkspaceItemsOnMainThread();  
  24.       ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();  
  25.       ArrayList<LauncherAppWidgetInfo> appWidgets =  
  26.               new ArrayList<LauncherAppWidgetInfo>();  
  27.       HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();  
  28.       HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();  
  29.       synchronized (sBgLock) {  
  30.           workspaceItems.addAll(sBgWorkspaceItems);  
  31.           appWidgets.addAll(sBgAppWidgets);  
  32.           folders.putAll(sBgFolders);  
  33.           itemsIdMap.putAll(sBgItemsIdMap);  
  34.       }  
  35.   
  36.       ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();  
  37.       ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();  
  38.       ArrayList<LauncherAppWidgetInfo> currentAppWidgets =  
  39.               new ArrayList<LauncherAppWidgetInfo>();  
  40.       ArrayList<LauncherAppWidgetInfo> otherAppWidgets =  
  41.               new ArrayList<LauncherAppWidgetInfo>();  
  42.       HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();  
  43.       HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();  
  44.   
  45.       // Separate the items that are on the current screen, and all the other remaining items  
  46.       filterCurrentWorkspaceItems(currentScreen, workspaceItems, currentWorkspaceItems,  
  47.               otherWorkspaceItems);  
  48.       filterCurrentAppWidgets(currentScreen, appWidgets, currentAppWidgets,  
  49.               otherAppWidgets);  
  50.       filterCurrentFolders(currentScreen, itemsIdMap, folders, currentFolders,  
  51.               otherFolders);  
  52.       sortWorkspaceItemsSpatially(currentWorkspaceItems);  
  53.       sortWorkspaceItemsSpatially(otherWorkspaceItems);  
  54.   
  55.       // Tell the workspace that we‘re about to start binding items  
  56.       r = new Runnable() {  
  57.           public void run() {  
  58.               Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  59.               if (callbacks != null) {  
  60.                   callbacks.startBinding();  
  61.               }  
  62.           }  
  63.       };  
  64.       runOnMainThread(r);  
  65.   
  66.       // Load items on the current page  
  67.       bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,  
  68.               currentFolders, null);  
  69.       if (isLoadingSynchronously) {  
  70.           r = new Runnable() {  
  71.               public void run() {  
  72.                   Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  73.                   if (callbacks != null) {  
  74.                       callbacks.onPageBoundSynchronously(currentScreen);  
  75.                   }  
  76.               }  
  77.           };  
  78.           runOnMainThread(r);  
  79.       }  
  80.   
  81.       // Load all the remaining pages (if we are loading synchronously, we want to defer this  
  82.       // work until after the first render)  
  83.       mDeferredBindRunnables.clear();  
  84.       bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,  
  85.               (isLoadingSynchronously ? mDeferredBindRunnables : null));  
  86.   
  87.       // Tell the workspace that we‘re done binding items  
  88.       r = new Runnable() {  
  89.           public void run() {  
  90.               Callbacks callbacks = tryGetCallbacks(oldCallbacks);  
  91.               if (callbacks != null) {  
  92.                   callbacks.finishBindingItems();  
  93.               }  
  94.   
  95.               // If we‘re profiling, ensure this is the last thing in the queue.  
  96.               if (DEBUG_LOADERS) {  
  97.                   Log.d(TAG, "bound workspace in "  
  98.                       + (SystemClock.uptimeMillis()-t) + "ms");  
  99.               }  
  100.   
  101.               mIsLoadingAndBindingWorkspace = false;  
  102.           }  
  103.       };  
  104.       if (isLoadingSynchronously) {  
  105.           mDeferredBindRunnables.add(r);  
  106.       } else {  
  107.           runOnMainThread(r);  
  108.       }  
  109.   }  
  1.   
*************************************************************************************************
 

Android Launcher源码结构

标签:

原文地址:http://www.cnblogs.com/cyqx/p/4739075.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!