Android Launcher分析和修改3——Launcher啟動和初始化


前面兩篇文章都是寫有關Launcher配置文件的修改,代碼方面涉及不多,今天開始進入Launcher代碼分析。

我們開機啟動Launcher,Launcher是由Activity Manager啟動的,而Activity Manager是由system server啟動。

原創博文,轉載請標明出處:http://www.cnblogs.com/mythou/p/3157452.html 

1、Launcher進程啟動過程

可以由下面圖看到Launcher進程是如何被創建啟動:

Activity Manager通過發送Intend來啟動Launcher。

 
         
//Edited by mythou
//http://www.cnblogs.com/mythou/
Intent intent = new Intent(mTopAction, mTopData != null ? 
Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL)
{ intent.addCategory(Intent.CATEGORY_HOME); }
startActivityLocked(
null, intent, null, null, 0, aInfo, null, null, 0, 0, 0, false, false);

因此,如果你要開機啟動一個替換Launcher的程序,只要在程序<intent-filter>里面加入action.MAIN 、

category.HOME、category.DEFAULT就可以。如果出現多個程序都加入這種intent,系統會彈出讓你選擇

哪個作為啟動器。

 

2、Launcher初始化——LauncherApplication。

Application類,我想大部分做Android應用的朋友都用過,每個Android應用默認都有一個Application類,

你也可以繼承Application類,然后加入自己代碼。Application是一個全局的應用類,在AndroidManifest.xml

我們也可以找到Application標簽。

 
         
//Edited by mythou
//http://www.cnblogs.com/mythou/
 <application android:name="com.android.launcher2.LauncherApplication" android:label="@string/application_name" android:icon="@drawable/ic_launcher_home" android:hardwareAccelerated="@bool/config_hardwareAccelerated" android:largeHeap="@bool/config_largeHeap" android:configChanges="locale"> </application>  

Android四大組件的聲明都需要放到application標簽里面,默認使用的是系統的Application類,如果你在項目

里面重載了它。就需要在標簽,name屬性下寫上你的新的Application類名。Launcher里面就是繼承了Application

LauncherApplication。應用啟動的時候首先會加載Application。

我們可以看到Launcher主類Launcher.java的onCreate函數里面,第一個就是獲取Application的實例。

LauncherApplication app = ((LauncherApplication)getApplication());

 

接下來我們看看LauncherApplication里面初始化,LauncherApplication大部分工作就是在初始化完成,剩下都是

一些返回接口。

 
         
//Edited by mythou
//http://www.cnblogs.com/mythou/
 @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;      //IconCahe里面保存了界面所有應用圖標的繪畫需要的數據,這個到時候具體分析再說。
//加入這東西的主要原因是為了提高繪畫界面的效率 mIconCache
= new IconCache(this); //數據庫加載類,LauncherModel是Launcher里面非常重要的一個類,相當於MVC模式里面的
     //Model功能,管理數據和初始化數據
mModel = new LauncherModel(this, mIconCache); //下面注冊了一些監聽器,主要包含APK文件更新刪除等數據變化的時候接收的通知
  //接收通知后,主要是用來更新Launcher里面的數據庫。因為桌面應用圖標數據,只會加載一次 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則是用於管理所有程序的contentprovider實例 ContentResolver resolver = getContentResolver(); //注冊內容觀察者,監聽application數據庫變化,回調 resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, mFavoritesObserver); }

上面是LauncherApplication最主要的工作,初始化整個Launcher的一些關鍵類,和注冊一些監聽器。主要都是用

來監聽應用的安裝更新刪除等導致Launcher數據庫變化的操作。Launcher數據都是使用contentprovider來提供數據。

其中注冊的監聽接口是

 
         
//Edited by mythou
//http://www.cnblogs.com/mythou/
    private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) {
       //重新加載界面數據 mModel.startLoader(LauncherApplication.
this, false); } };
LauncherSettings.Favorites.CONTENT_URI里面數據發生變化的時候,都會調用mModel.startLoader()接口,
重新加載Launcher的數據。startLoader的具體操作,我后面分析LauncherModel類的時候會分析。這一塊涉及
Launcher所有數據加載。
剩下的接都是返回初始化時候創建的對象或者獲取屏幕密度、獲取是否大屏幕。
后面很多處理都需要判斷是否是大屏幕,4.0以后手機平板都共用一套系統,導致多了很多處理。

 

3、Launcher.java初始化

Launcher.java是Launcher里面最主要的類,是一個Activity。啟動的第一個組件。既然是Activity,我們要分析它

初始化,毫無疑問,需要找到onCreate()里面分析。把主要一些分析用注釋方式寫在代碼里面,這樣比較方便閱讀。

 

 
         
//Edited by mythou
//http://www.cnblogs.com/mythou/
 @Override protected void onCreate(Bundle savedInstanceState) 
  { super.onCreate(savedInstanceState);
//獲取Application 實例 LauncherApplication app = ((LauncherApplication)getApplication());
     //LauncherModel類里面獲取Launcher的對象引用 mModel
= app.setLauncher(this);
//獲取IconCache,IconCache在Application里面初始化     mIconCache
= app.getIconCache(); mDragController = new DragController(this); mInflater = getLayoutInflater(); mAppWidgetManager = AppWidgetManager.getInstance(this); //監聽widget改變,以后在Model里面回調處理的結果 mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); mAppWidgetHost.startListening();
     //這個是設置Launcher的跟蹤調試文件,下面很多信息會寫到這個文件里面。
if (PROFILE_STARTUP)
     { android.os.Debug.startMethodTracing( Environment.getExternalStorageDirectory()
+ "/launcher"); } //讀取本地配置,保存更新配置,清空IconCache checkForLocaleChange(); setContentView(R.layout.launcher); //對所有的UI控件進行加載和配置 setupViews(); //顯示操作提示,第一次啟動的時候才會顯示 showFirstRunWorkspaceCling(); //注冊監控Launcher數據庫變化 registerContentObservers();      //鎖住APP,初始化不能操作。 lockAllApps(); mSavedState = savedInstanceState; restoreState(mSavedState); // Update customization drawer _after_ restoring the states if (mAppsCustomizeContent != null)
     { mAppsCustomizeContent.onPackagesUpdated(); }
if (PROFILE_STARTUP)
     { android.os.Debug.stopMethodTracing(); }
//加載啟動數據,所有界面數據(快捷方式、folder、widget、allApp)等在loader里面加載,這部分后面我會詳細分析。 if (!mRestoring) { mModel.startLoader(this, true); } if (!mModel.isAllAppsLoaded())
     { ViewGroup appsCustomizeContentParent
= (ViewGroup) mAppsCustomizeContent.getParent(); mInflater.inflate(R.layout.apps_customize_progressbar, appsCustomizeContentParent); } // For handling default keys mDefaultKeySsb = new SpannableStringBuilder(); Selection.setSelection(mDefaultKeySsb, 0); IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); registerReceiver(mCloseSystemDialogsReceiver, filter);
     //下面這幾個就是Android原生界面上的Market、搜索、聲音輸入按鈕的默認圖標顯示。 boolean searchVisible
= false; boolean voiceVisible = false; // If we have a saved version of these external icons, we load them up immediately 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);
// On large interfaces, we want the screen to auto-rotate based on the current orientation if (LauncherApplication.isScreenLarge() || Build.TYPE.contentEquals("eng"))
     { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } Log.i(TAG,
"------------------------>Launcher init over") ; }

 上面就是Launcher.java的初始化,大部分我都寫了注釋。其實這里最主要的工作是加載界面數據:

mModel.startLoader(this, true); 這塊實現是在LauncherModel里面實現的。下一篇文章,我會詳細

說明如何加載和獲取管理系統里面的APP相關數據。

 

今天就講到這里,如發現問題,請留言指出,歡迎留言討論。

 

 相關系列文章:

Android Launcher分析和修改1——Launcher默認界面配置(default_workspace)

Android Launcher分析和修改2——Icon修改、界面布局調整、壁紙設置

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM