Android Launcher 分析

來源:互聯網
上載者:User
1. Launcher的啟動過程

從網路上找了一段關於Launcher的啟動過程的文章,作為學習Launcher的背景知識:

Linux kernel啟動以後會通過app_main進程來初始化android Runtime Java運行環境,而zygote是Android的第一個進程。所有的android的應用以及大部分系統服務都是通過zygote fork出來的子進程(我現在看到的只有native的service manager不是zygote fork出來的)。在system server中啟動的若干系統服務中與我們啟動進程相關的就是Acitivity Manager。

  當systerm server啟動好所有服務以後,系統就進入”system ready”狀態,這個時候Activity Manager就登場了。Activity Manager光看程式碼就知道是一個重量級的服務,它主要管理Activity之間的跳轉,以及進程的生命週期。當Activity Manager發現系統已經啟動好以後它就會發出一個intent:

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);  }  

通過這個category類型為home的intent,Activity Manager就會通過:

startActivityLocked(null, intent, null, null, 0, aInfo,   null, null, 0, 0, 0, false, false);  

啟動Home進程了。而這個啟動Home進程的過程實際上還是去通過zygote fork出的一個子進程。
因此只要在manifest中具備這樣的intent-filter都可以在開機的時候作為Home啟動:

<intent-filter>  <action android:name="android.intent.action.MAIN" />  <category android:name="android.intent.category.HOME"/>  <category android:name="android.intent.category.DEFAULT" />  </intent-filter> 

多個home之間的switch會在開始的時候有個選擇,至於這個選擇好像是package manager來實現的,沒有仔細研究過。

2.UI結構
通過launcher/Res/Layout-land/launcher.xml分析可以得到主畫面的UI結構:

整個homescreen是一個包含三個child view的FrameLayout(com.android.launcher.DragLayer)。

第一個child就是案頭com.android.launcher.Workspace。這個案頭又包含三個child。每個child就對應一個案頭。這就是你在Android上看到的三個案頭。每個案頭上可以放置下列對象:應用捷徑,appwidget和folder。

第二個child是一個SlidingDrawer控制項,這個控制項由兩個子控制群組成。一個是com.android.launcher.HandleView,就是Android案頭下方的把手,當點擊這個把手時,另一個子控制項,com.android.launcher.AllAppsGridView就會彈出,這個子控制項列出系統中當前安裝的所有類型為category.launcher的Activity。

第三個child是com.android.launcher.DeleteZone。當使用者在案頭上長按一個widget時,把手位置就會出現一個垃圾桶形狀的控制項,就是這個控制項。

3.應用程式程式碼分析
由Launcher中的AndroidManifest.xml可以看出整個Launcher的代碼結構。


首先,是一些許可權的聲明。例如:

<uses-permission android:name="android.permission.CALL_PHONE" />  <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />  

這部分可以略過;

其次,Application的構成,如:

(1)Launcher:HomeScreen的Activity。

<intent-filter>   <action android:name="android.intent.action.MAIN" />   <category android:name="android.intent.category.HOME"/>   <category android:name="android.intent.category.DEFAULT" />  <category android:name="android.intent.category.MONKEY" /> </intent-filter>  

上面這段代碼就標誌著它是開機啟動後Home的Activity。通過Launcher.java中onCreate()的分析我們可以大致把握螢幕的主要活動:

protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);  //把xml檔案的內容執行個體化到View中          mInflater = getLayoutInflater();  //監聽應用程式控制項改變事件          mAppWidgetManager = AppWidgetManager.getInstance(this);          mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);          mAppWidgetHost.startListening();  // 用於調試?              if (PROFILE_STARTUP) {              android.os.Debug.startMethodTracing("/sdcard/launcher");          }    //監聽locale,mcc,mnc是否改變,如果改變,則重寫新配置        //mcc:mobile country code(國家代碼China 460); mnc:mobile network code(網路代碼)          checkForLocaleChange();         /*This allows such applications to have a virtual wallpaper that is larger than the physical screen, matching the size of their workspace.*/          setWallpaperDimension();  //顯示主畫面UI元素,workspace,slidingdrawer(handleview and appgridview),deletezone          setContentView(R.layout.launcher);  //Finds all the views we need and configure them properly.  //完成workspace,slidingdrawer,deletezone的各種事件操作和監聽          setupViews();  //Registers various intent receivers.  //允許其他應用對本應用的操作          registerIntentReceivers();  //Registers various content observers.  //例如,註冊一個內容觀察者跟蹤喜愛的應用程式          registerContentObservers();  //重新儲存前一個狀態(目的??)          mSavedState = savedInstanceState;          restoreState(mSavedState);  //調試?          if (PROFILE_STARTUP) {              android.os.Debug.stopMethodTracing();          }  //Loads the list of installed applications in mApplications.          if (!mRestoring) {              startLoaders();          }          // For handling default keys??          mDefaultKeySsb = new SpannableStringBuilder();          Selection.setSelection(mDefaultKeySsb, 0);      }  

方法onActivityResult():完成在workspace上增加shortcut,appwidge和Livefolder;

方法onSaveInstantceState()和onRestoreInstanceState():為了防止Sensor、Land和Port布局自動切換時資料被置空,通過onSaveInstanceState方法可以儲存當前視窗的狀態,在即將布局切換前將當前的Activity壓入曆史堆棧。如果我們的Activity在後台沒有因為運行記憶體吃緊被清理,則切換時回觸發onRestoreIntanceState()。
(2)WallpaperChooser:設定牆紙。
同理我們從onCreate()作為入口來分析這個活動的主要功能。

public void onCreate(Bundle icicle) {          super.onCreate(icicle);  //設定允許改變的視窗狀態,需在 setContentView 之前調用          requestWindowFeature(Window.FEATURE_NO_TITLE);  / /添加牆紙資源,將資源標識符加入到動態數組中          findWallpapers();  //顯示牆紙設定螢幕的UI元素,Imageview,Gallery and Button(LinearLayout)          setContentView(R.layout.wallpaper_chooser);  //圖片查看功能的實現          mGallery = (Gallery) findViewById(R.id.gallery);          mGallery.setAdapter(new ImageAdapter(this));          mGallery.setOnItemSelectedListener(this);          mGallery.setCallbackDuringFling(false);  //Button事件監聽,點擊選擇setWallpaper(Resid)          findViewById(R.id.set).setOnClickListener(this);          mImageView = (ImageView) findViewById(R.id.wallpaper);      }  

(3)default_searchable

對於home中任意的Acitivty,使能系統預設Search模式,這樣就可以使用android系統預設的search UI。

(4)InstallShortcutReceiver

繼承自BroadcastReceiver,重寫onReceiver()方法,對於發送來的Broadcast(這裡指Intent)進行過濾(IntentFilter)並且響應(這裡是InstallShortcut())。這裡分析下onReceive():

<!-- Enable system-default search mode for any activity in Home -->  <!-- Intent received used to install shortcuts from other applications -->  public void onReceive(Context context, Intent data) {         //接受並過濾Intent  if (!ACTION_INSTALL_SHORTCUT.equals(data.getAction())) {              return;          }        //擷取螢幕          int screen = Launcher.getScreen();  //安裝捷徑          if (!installShortcut(context, data, screen)) {              //如果螢幕已滿,搜尋其他螢幕              for (int i = 0; i < Launcher.SCREEN_COUNT; i++) {                  if (i != screen && installShortcut(context, data, i)) break;              }          }      }  

其中IntallShortcut()方法:首先,對傳入的座標進行判斷(findEmptyCell()),如果是空白位置,則可以放置捷徑;其次,預設情況下,我們允許建立重複的捷徑,具體建立過程(addShortcut())就是把捷徑的資訊傳入資料庫(addItemToDatabase())。
(5)UninstallShortcutReceiver:

同理,UninstallShortcutReceiver()繼承自BroadcastReceiver(),實現onReceiver()方法。定義一個ContentResolver對象完成對資料庫的訪問和操作(通過URI定位),進而刪除捷徑 。

(6)LauncherProvider:

繼承自ContentProvider(),主要是建立一個資料庫來存放HomeScreen中的資料資訊,並通過內容提供者來實現其他應用對launcher中資料的訪問和操作。
重寫了ContentProvider()中的方法:
getType():返回資料類型。如果有自訂的全新類型,通過此方法完成資料的訪問。
query():查詢資料。傳入URI,返回一個Cursor對象,通過Cursor完成對資料庫資料的遍曆訪問。
Insert():插入一條資料。
bulkInsert():大容量資料的插入。
delete():刪除一條資料。
update():更改一條資料。
sendNotify():發送通知。
類DatabaseHelper繼承自一個封裝類SQLiteOpenHelper(),方便了資料庫的管理和維護。
重寫的方法:
onCreate():建立一個表。其中db.execSQL()方法執行一條SQL語句,通過一條字串執行相關的操作。當然,對SQL基本語句應該瞭解。
onUpgrade():升級資料庫。
對HomeScreen資料庫操作的一些方法:
addClockWidget(),addSearchWidget,addShortcut,addAppShortcut,
loadFavorites(),launcherAppWidgetBinder(),convertWidget(),updateContactsShortcuts(),
copyFromCursor()
補充:
類AddAdapter(AddAdapter.java)列出了這四個類型對象。當使用者在案頭空白處長按時,下列函數序列被執行:
Launcher::onLongClick -->
Launcher::showAddDialog -->
Launcher::showDialog(DIALOG_CREATE_SHORTCUT); -->
Launcher::onCreateDialog -->
Launcher::CreateShortcut::createDialog:這個函數建立一個彈出式對話方塊,詢問使用者是要添加什麼(捷徑,appwidget, 檔案夾和牆紙)其內容就來自AddAdapter。
類DesktopItemsLoader負責將案頭上所有的對象從content provider中提取。
線程private ApplicationsLoader mApplicationsLoader負責從包管理器中擷取系統中安裝的應用列表。(之後顯示在AllAppsGridView上)。ApplicationsLoader::run實現:
1)通過包管理器列出系統中所有類型為Launcher,action為MAIN的activity;
2)對每一個Activity,
      a) 將Activity相關中繼資料資訊,如title, icon, intent等緩衝到appInfoCache;
        b) 填充到ApplicationsAdapter 中。填充過程中用到了一些小技巧,每填充4(UI_NOTIFICATION_RATE)個activity更新一下相應view。

在Launcher::onCreate中,函數startLoaders被調用。而該函數接著調用loadApplications和loadUserItems,分別擷取系統的應用列表,以及顯示在案頭上的對象列表(捷徑,appwidget,folder等)。
Launcher上排列的所有應用表徵圖由AllAppsGridView對象呈現。這個對象是一個GridView。其對應的Adapter是ApplicationsAdapter,對應的model則是ApplicationInfo數組。數組內容是由ApplicationsLoader裝載的。



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.