? ? 最近研究ICS4.0的Launcher,發現4.0和2.3有稍微點區別,但是區別不是特別大,所以我就先整理一下Launcher啟動的大致流程。 Launcher其實是貫徹于手機的整個系統的,時時刻刻都在運行,要是Launcher不運行了,手機就得黑屏了。Launcher的 LauncherMode=singletask,所以說不管Launcher啟動了哪個應用,總有個Launcher的實例在堆棧中,并且位于棧底。點 擊Home鍵進入到Launcher,上篇Android的全局鍵(home鍵/長按耳機鍵)詳解【android源碼解析八】?中有詳細的介紹。大致思路其實就是啟動launcher的時候,新啟動一個task。大致先說這么多,先看截圖:
?
?
?????????????????????????????????????
?
?????????????????????????????????????????????????????????????????????????? 圖(1)
????? 上圖是4.0的Launcher界面,下面我們分步來解析一下Launcher的啟動過程。
?
???? Step 0:首先要給大家介紹一下Launcher的數據庫,這個數據庫中存放著待機界面的圖標,主屏底部的應用程序圖標和桌面folder中各應用程序的圖 標,ICS4.0的folder中只能放應用程序的快捷方式,shortcut不能放到這個folder中,先看截圖:?
?
??????????????????????????????????????????????????????????????????????? 圖(2)
????? ?說說各字段的含義:
??????????????? title:表示桌面應用程序的名字,有的title為空,表示是widget的快捷方式;
?????????????intent:表示啟動這個圖標的intent放到數據庫中,當click的時候就會調用這個字段,啟動相應的應用程序;
???????container:表示應用程序的容器,folder的容器為整數,-100:表示在桌面的程序,-101:表示是主屏底部的程序;
???????????screen:表示在第幾個屏,folder的screen都是0, container=-101的為0,1,3,4;2為allapp的按鈕;
?????????????? cellX:表示在屏幕X軸的位置,(0,1,2,3),左上角為0點,往右依次增加;
???????????????cellY:表示在屏幕Y軸的位置,(0,1,2,3),左上角為0點,往下依次增加;
????????????? spallX:表示占X軸幾個格;
????????????? spallY:表示占Y軸幾個格;
???????? itemType:應用程序用0表示,shortcut用1表示,folder用2表示,widget用4表示;
??? appWidgetId:-1表示不是widget,數字大于0表示才是widget;
???????isShortCut:值為0表示不是應用程序的ShortCut,值為1表示是應用程序的ShortCut;
???????? iconType:值為0表示圖標的名字被定義為包名的資源id,值為1表示圖標用bitmap保存;
???????????????? icon:表示應用程序的圖標,二進制的;顯示為一張圖片;
?????? 說明:folder中的應用快捷方式綁定folder---->是用container的值綁定folder的id的;
??????? 詳細的講解請參考LauncherSettings.java這個類,有數據庫字段的詳細講解;
?????????手 機是在第一次燒機完成后,數據庫的值還沒有,這時候launcher解析default_workspace.xml把這個值存到數據庫中;所以說想定制 什么樣的開機桌面就在default_workspace.xml中做相應的配置,具體參照我前面的博客:
Android中源碼Launcher主屏幕程序排列詳解【安卓Launcher進化一】中有詳細的介紹:
?????? i f (!convertDatabase(db))?{
??????????????? ?// Populate favorites table with initial favorites
??????????????? loadFavorites(db, R.xml.default_workspace);
????????}
?
??????Step?1:開機后先啟動LauncherApplication.java這個類的onCreate()方法,下面看代碼:???
???
Java代碼??
@Override???public?void?onCreate()?{???????super.onCreate();???????????????????final?int?screenSize?=?getResources().getConfiguration().screenLayout?&???????????????Configuration.SCREENLAYOUT_SIZE_MASK;???????sIsScreenLarge?=?screenSize?==?Configuration.SCREENLAYOUT_SIZE_LARGE?||???????????screenSize?==?Configuration.SCREENLAYOUT_SIZE_XLARGE;???????sScreenDensity?=?getResources().getDisplayMetrics().density;??????????????mIconCache?=?new?IconCache(this);????????????mModel?=?new?LauncherModel(this,?mIconCache);???????????????????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);???????filter.addAction(Intent.ACTION_LOCALE_CHANGED);???????filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);???????registerReceiver(mModel,?filter);???????filter?=?new?IntentFilter();???????filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);???????registerReceiver(mModel,?filter);???????filter?=?new?IntentFilter();???????filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);???????registerReceiver(mModel,?filter);???????????????????ContentResolver?resolver?=?getContentResolver();???????resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI,?true,???????????????mFavoritesObserver);???}?? ? ???????Step 2:在LauncherApplication.java中onTerminate()的方法,解除監聽的綁定;
?
Java代碼??
???@Override?????public?void?onTerminate()?{?????????super.onTerminate();???????????unregisterReceiver(mModel);???????????ContentResolver?resolver?=?getContentResolver();?????????resolver.unregisterContentObserver(mFavoritesObserver);?????}?? ?
???? Step 3:Step1中的數據庫mFavoritesObserver監聽內部類如下:
?
Java代碼??
?private?final?ContentObserver?mFavoritesObserver?=?new?ContentObserver(new?Handler())?{???????@Override???????public?void?onChange(boolean?selfChange)?{???????????mModel.startLoader(LauncherApplication.this,?false);???????}???};?? ?
說明:mModel.startLoader(。。,。。)是開啟一個線程,設置線程的優先級NORM_PRIORITY,開始load桌面圖標對應的數據庫,這個過程是和Launcher.onCreate()同時進行的;
????Step 4: 接著我們來看看mModel.startLoader(LauncherApplication.this, false)的方法:
?
Java代碼??
public?void?startLoader(Context?context,?boolean?isLaunching)?{???????synchronized?(mLock)?{???????????if?(DEBUG_LOADERS)?{???????????????Log.d(TAG,?"startLoader?isLaunching="?+?isLaunching);???????????}??????????????????????if?(mCallbacks?!=?null?&&?mCallbacks.get()?!=?null)?{?????????????????????????????????????????isLaunching?=?isLaunching?||?stopLoaderLocked();???????????????mLoaderTask?=?new?LoaderTask(context,?isLaunching);???????????????sWorkerThread.setPriority(Thread.NORM_PRIORITY);???????????????sWorker.post(mLoaderTask);???????????}???????}???}?? ??
?? Step 5:接著我們來看看LoaderTask.java的run()方法:
Java代碼??
public?void?run()?{??????????????????final?Callbacks?cbk?=?mCallbacks.get();??????final?boolean?loadWorkspaceFirst?=?cbk?!=?null???(!cbk.isAllAppsVisible())?:?true;????????keep_running:?{??????????????????????????synchronized?(mLock)?{??????????????if?(DEBUG_LOADERS)?Log.d(TAG,?"Setting?thread?priority?to?"?+??????????????????????(mIsLaunching???"DEFAULT"?:?"BACKGROUND"));??????????????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");??????????????loadAndBindWorkspace();??????????}?else?{??????????????if?(DEBUG_LOADERS)?Log.d(TAG,?"step?1:?special:?loading?all?apps");??????????????loadAndBindAllApps();??????????}????????????if?(mStopped)?{??????????????break?keep_running;??????????}????????????????????????????synchronized?(mLock)?{??????????????if?(mIsLaunching)?{??????????????????if?(DEBUG_LOADERS)?Log.d(TAG,?"Setting?thread?priority?to?BACKGROUND");??????????????????android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);??????????????}??????????}??????????waitForIdle();????????????????????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();??????????}????????????????????synchronized?(mLock)?{??????????????android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);??????????}??????}??????????????if?(DEBUG_LOADERS)?Log.d(TAG,?"Comparing?loaded?icons?to?database?icons");??????for?(Object?key?:?sDbIconCache.keySet())?{??????????updateSavedIcon(mContext,?(ShortcutInfo)?key,?sDbIconCache.get(key));??????}??????sDbIconCache.clear();????????????????mContext?=?null;????????synchronized?(mLock)?{??????????????????if?(mLoaderTask?==?this)?{??????????????mLoaderTask?=?null;??????????}??????}??}????public?void?stopLocked()?{??????synchronized?(LoaderTask.this)?{??????????mStopped?=?true;??????????this.notify();??????}??}?? ?
加載桌面圖標對應的數據庫的值,這些值能把這些圖標顯示在屏幕上。
?
?
??? Step 6:LauncherApplication.onCreate()方法啟動完成后,接著開始調用Launcher.java的onCreate()方法。代碼如下:
Java代碼??
@Override??protected?void?onCreate(Bundle?savedInstanceState)?{??????super.onCreate(savedInstanceState);??????????LauncherApplication?app?=?((LauncherApplication)getApplication());??????????????mModel?=?app.setLauncher(this);??????????mIconCache?=?app.getIconCache();??????????mDragController?=?new?DragController(this);??????????mInflater?=?getLayoutInflater();????????????mAppWidgetManager?=?AppWidgetManager.getInstance(this);??????????mAppWidgetHost?=?new?LauncherAppWidgetHost(this,?APPWIDGET_HOST_ID);??????????mAppWidgetHost.startListening();????????if?(PROFILE_STARTUP)?{??????????android.os.Debug.startMethodTracing(??????????????????Environment.getExternalStorageDirectory()?+?"/launcher");??????}????????????checkForLocaleChange();??????????setContentView(R.layout.launcher);??????????setupViews();??????????????????????showFirstRunWorkspaceCling();????????????registerContentObservers();????????lockAllApps();????????mSavedState?=?savedInstanceState;??????restoreState(mSavedState);????????????if?(mAppsCustomizeContent?!=?null)?{??????????mAppsCustomizeContent.onPackagesUpdated();??????}????????if?(PROFILE_STARTUP)?{??????????android.os.Debug.stopMethodTracing();??????}????????if?(!mRestoring)?{??????????mModel.startLoader(this,?true);??????}????????if?(!mModel.isAllAppsLoaded())?{??????????ViewGroup?appsCustomizeContentParent?=?(ViewGroup)?mAppsCustomizeContent.getParent();??????????mInflater.inflate(R.layout.apps_customize_progressbar,?appsCustomizeContentParent);??????}????????????mDefaultKeySsb?=?new?SpannableStringBuilder();??????Selection.setSelection(mDefaultKeySsb,?0);????????????IntentFilter?filter?=?new?IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);??????registerReceiver(mCloseSystemDialogsReceiver,?filter);????????boolean?searchVisible?=?false;??????boolean?voiceVisible?=?false;??????????????int?coi?=?getCurrentOrientationIndexForGlobalIcons();??????if?(sGlobalSearchIcon[coi]?==?null?||?sVoiceSearchIcon[coi]?==?null?||??????????????sAppMarketIcon[coi]?==?null)?{??????????updateAppMarketIcon();??????????searchVisible?=?updateGlobalSearchIcon();??????????voiceVisible?=?updateVoiceSearchIcon(searchVisible);??????}??????if?(sGlobalSearchIcon[coi]?!=?null)?{???????????updateGlobalSearchIcon(sGlobalSearchIcon[coi]);???????????searchVisible?=?true;??????}??????if?(sVoiceSearchIcon[coi]?!=?null)?{??????????updateVoiceSearchIcon(sVoiceSearchIcon[coi]);??????????voiceVisible?=?true;??????}??????if?(sAppMarketIcon[coi]?!=?null)?{??????????updateAppMarketIcon(sAppMarketIcon[coi]);??????}??????mSearchDropTargetBar.onSearchPackagesChanged(searchVisible,?voiceVisible);????????????if?(LauncherApplication.isScreenLarge()?||?Build.TYPE.contentEquals("eng"))?{??????????setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);??????}??}?? ?
??? Step 7:其中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?void?bindPackagesUpdated();?????????public?boolean?isAllAppsVisible();?????????public?void?bindSearchablesChanged();?????}?? ?
?
對LauncherModel進行初始化的時候mModel = app.setLauncher(this);---->mModel.initialize(launcher);----->
???????????? ?public void initialize(Callbacks callbacks) {
????????????????????? synchronized (mLock) {
????????????????????????????? mCallbacks = new WeakReference<Callbacks>(callbacks);
????????????????????? ?}
?????????????? }
這 個callbacks就是定義的接口回調,具體實現是在Launcher.java中定義的,啟動Launcher的過程中,這些實現是異步來實現的。還 有Launcher.java的onResume()方法沒有講解,到這兒基本上Android的Launcher已經啟動起來了,這個 onResume()我研究后再更新。
????? 歡迎各界同僚留言指正錯誤和拍磚!歡迎留言!
轉載于:https://www.cnblogs.com/xiaochao1234/p/4054109.html
總結
以上是生活随笔為你收集整理的Android4.0源码Launcher启动流程分析【android源码Launcher系列一】的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。