本文出自:http://blog.csdn.net/lilu_leo/article/details/6988326java
第一步:咱們先從LauncherApplication.java開始,先找到onCreate()方法:android
public void onCreate() { //設置最小堆內存8M VMRuntime.getRuntime().setMinimumHeapSize(8 * 1024 * 1024); //llx modify the heapsize super.onCreate(); //創建應用圖標緩存器 mIconCache = new IconCache(this); //創建LauncherModel mModel = new LauncherModel(this, mIconCache); // Register intent receivers //註冊Intent.ACTION_PACKAGE_ADDED,Intent.ACTION_PACKAGE_REMOVED, //Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE, //Intent.ACTION_LOCALE_CHANGED 事件監聽器 //LauncherModel做爲廣播接收器對上面事件進行監聽 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); registerReceiver(mModel, filter); filter = new IntentFilter(); filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); registerReceiver(mModel, filter); filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); registerReceiver(mModel, filter); // Register for changes to the favorites //添加對桌面favorites content provider 數據變化監聽器 ContentResolver resolver = getContentResolver(); resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,mFavoritesObserver); }
第二步:看下Launcher.java中的onCreate()方法:數據庫
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //獲取LauncherApplication LauncherModel mIconCache等LauncherApplication初始化的對象 LauncherApplication app = ((LauncherApplication)getApplication()); mModel = app.setLauncher(this); mIconCache = app.getIconCache(); //新建拖放控制器new DragController(this) mDragController = new DragController(this); mInflater = getLayoutInflater(); //獲取桌面組件管理器,啓動桌面組件host mAppWidgetManager = AppWidgetManager.getInstance(this); mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); mAppWidgetHost.startListening(); if (PROFILE_STARTUP) { android.os.Debug.startMethodTracing("/sdcard/launcher"); } //從array.hotseats中加載全部的hotseats loadHotseats(); //從加載本地設置 checkForLocaleChange();setWallpaperDimension(); //加載佈局文件 setContentView(R.layout.launcher); //初始化全部控件 setupViews(); registerContentObservers(); lockAllApps(); //從Bundle savedInstanceState獲取桌面持久化數據 mSavedState = savedInstanceState; restoreState(mSavedState); if (PROFILE_STARTUP) { android.os.Debug.stopMethodTracing(); } if (!mRestoring) { //LauncherModel.Loader.startLoader() 代碼同步處理 mModel.startLoader(this, true); } // For handling default keys mDefaultKeySsb = new SpannableStringBuilder(); Selection.setSelection(mDefaultKeySsb, 0); //註冊Intent.ACTION_CLOSE_SYSTEM_DIALOGS廣播監聽 IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); registerReceiver(mCloseSystemDialogsReceiver, filter); }
第三步:加載桌面項:在LauncherModel.java的Thread的run方法,是在主線程完成之後纔開始加載。緩存
public void run() { // 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). final Callbacks cbk = mCallbacks.get(); final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true; 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) { android.os.Process.setThreadPriority(mIsLaunching ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND); } //判斷是否先加載桌面 if (loadWorkspaceFirst) { if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace"); //從數據庫launcher.db中查詢中全部桌面項構造對應類型的ItemInfo對象存入 loadAndBindWorkspace(); } else { if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps"); loadAndBindAllApps(); } 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) { android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } } waitForIdle(); // second step if (loadWorkspaceFirst) { if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps"); loadAndBindAllApps(); } else { if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace"); loadAndBindWorkspace(); } }
這裏調用了Launcher.java中startBinding方法app
public void startBinding() { final Workspace workspace = mWorkspace; int count = workspace.getChildCount(); for (int i = 0; i < count; i++) { // Use removeAllViewsInLayout() to avoid an extra requestLayout() and invalidate(). ((ViewGroup) workspace.getChildAt(i)).removeAllViewsInLayout(); } if (DEBUG_USER_INTERFACE) { android.widget.Button finishButton = new android.widget.Button(this); finishButton.setText("Finish"); workspace.addInScreen(finishButton, 1, 0, 0, 1, 1); finishButton.setOnClickListener(new android.widget.Button.OnClickListener() { public void onClick(View v) { finish(); } }); } }
還有Launcher.java的bindItem()方法異步
public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end) { setLoadOnResume(); //獲取桌面的celllayout對象,也就是workspace下5個用戶桌面中的一個 final Workspace workspace = mWorkspace; for (int i=start; i<end; i++) { //根據ItemInfo對象建立桌面圖標view對象 final ItemInfo item = shortcuts.get(i); mDesktopItems.add(item); switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: final View shortcut = createShortcut((ShortcutInfo)item); //獲取item.screen, item.cellX, item.cellY, spanX, spanY並添加到屏幕上。 workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1,false); break; case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()), (UserFolderInfo) item); workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1,false); break; case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: final FolderIcon newLiveFolder = LiveFolderIcon.fromXml( R.layout.live_folder_icon, this, (ViewGroup) workspace.getChildAt(workspace.getCurrentScreen()), (LiveFolderInfo) item); workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1,false); break; } } //.從新設置桌面圖標view 的layoutparam(類型爲cellLayout.layoutparam) workspace.requestLayout(); }
注意,這兩個方法都是異步調用。緣由應該很清楚:時間。
ide
另外還要注意一下兩點:
佈局
1.桌面圖標view對象添加OnLongClickListener=laucher,由laucher負責監聽桌面圖標view的longclick事件
ui
2.若是桌面圖標是DropTarget對象,拖放控制器mDragController添加該view到拖放目的地列表this
在Launcher.java的代碼中有bindFolders()和bindAppWidget()方法,都是回調方法。主要看下bindAppWidget()方法吧。
/** * Add the views for a widget to the workspace. * * Implementation of the method from LauncherModel.Callbacks. */ public void bindAppWidget(LauncherAppWidgetInfo item) { setLoadOnResume(); final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0; if (DEBUG_WIDGETS) { Log.d(TAG, "bindAppWidget: " + item); } final Workspace workspace = mWorkspace; //獲取LauncherAppWidgetInfo的appWidgetId final int appWidgetId = item.appWidgetId; //根據appWidgetInfo建立桌面組件的view AppWidgetHostView對象 final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); if (DEBUG_WIDGETS) { Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider); } item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); item.hostView.setAppWidget(appWidgetId, appWidgetInfo); item.hostView.setTag(item); //添加到對應桌面的cell workspace.addInScreen(item.hostView, item.screen, item.cellX, item.cellY, item.spanX, item.spanY, false); workspace.requestLayout(); mDesktopItems.add(item); if (DEBUG_WIDGETS) { Log.d(TAG, "bound widget id="+item.appWidgetId+" in " + (SystemClock.uptimeMillis()-start) + "ms"); } } <span style="font-size:16px;"> </span>
當都加載完成之後會執行finishBindingItems():
/** * Callback saying that there aren't any more items to bind. * * Implementation of the method from LauncherModel.Callbacks. */ public void finishBindingItems() { setLoadOnResume(); if (mSavedState != null) { if (!mWorkspace.hasFocus()) { mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus(); } final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS); if (userFolders != null) { for (long folderId : userFolders) { final FolderInfo info = sFolders.get(folderId); if (info != null) { openFolder(info); } } final Folder openFolder = mWorkspace.getOpenFolder(); if (openFolder != null) { openFolder.requestFocus(); } } mSavedState = null; } if (mSavedInstanceState != null) { super.onRestoreInstanceState(mSavedInstanceState); mSavedInstanceState = null; } mWorkspaceLoading = false; }
前面那三個都是都是回調方法,控制器固然是LauncherModel.java了,讓咱們在代碼裏看一下:
其接口定義以下:
public interface Callbacks { public boolean setLoadOnResume(); public int getCurrentWorkspaceScreen(); public void startBinding(); public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end); public void bindFolders(HashMap<Long,FolderInfo> folders); public void finishBindingItems(); public void bindAppWidget(LauncherAppWidgetInfo info); public void bindAllApplications(ArrayList<ApplicationInfo> apps); public void bindAppsAdded(ArrayList<ApplicationInfo> apps); public void bindAppsUpdated(ArrayList<ApplicationInfo> apps); public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent); public boolean isAllAppsVisible(); }
想看仔細的,本身能夠在代碼中找一下。最後執行bindAllApplications(), bindAppsAdded()方法:
public void bindAllApplications(ArrayList<ApplicationInfo> apps) { mAllAppsGrid.setApps(apps); } /** * A package was installed. * * Implementation of the method from LauncherModel.Callbacks. */ public void bindAppsAdded(ArrayList<ApplicationInfo> apps) { setLoadOnResume(); removeDialog(DIALOG_CREATE_SHORTCUT); mAllAppsGrid.addApps(apps); }
到這基本上就是整個的啓動過程了。