About Widget 2
上一篇是對Dev Guide中關于SDK的翻譯,這篇文章的目的就是對AppWidget有一個深入的介紹。
一、首先介紹一下在開機過程中系統對AppWidget做了什么
當SystemServer.java運行到init2()的時候,通過SystemManager.addService(Context.AppWidget_Service,appWidget)將AppWidgetService服務加到服務隊列里面,當所有服務加載完畢后會調用appWidgetF.systemReady(safeMode)進入到AppWidgetService.java,在這個方法中做了三件事:
1、遍歷所有的安裝包,找到符合條件的ACTION:ACTION_APPWIDGET_UPDATE和<meta-data android:name="android.appwidget.provider"/>的receiver,解析相關信息,保存到本地數據成員中。
2、讀取本地文件數據:/data/system/appwidgets.xml,所有已安裝到桌面的widget的信息都保存在這個文件里。讀出來,也保存到本地數據成員里。
3、注冊了三個消息:ACTION_BOOT_COMPLETED(系統啟動到桌面就會發送此消息),ACTION_PACKAGE_ADDED(有新 APK包安裝到系統),ACTION_PACKAGE_REMOVED(有APK包被刪除)。當系統啟動到桌面后,AppWidgetService接收 到了ACTION_BOOT_COMPLETED消息,它會去檢查本地數據成員,如果有已經安裝到桌面的widget,它會上發 ACTION_APPWIDGET_ENABLED和ACTION_APPWIDGET_UPDATE消息。如果有widget設置了updatePeriodMillis的屬性,它就會開始計時(這個是通過AlarmManager來實現的),到時間時,就會再次發送ACTION_APPWIDGET_UPDATE消息。
二、與AppWidget相關的類有:
RemoteViews.java
* A class that describes a view hierarchy that can be displayed in
* another process. The hierarchy is inflated from a layout resource
* file, and this class provides some basic operations for modifying
* the content of the inflated hierarchy
上面是Google給的關于RemoteViews的解釋,大家不要被它的名字給欺騙了,說白了它就是作為一個描述view信息的載體,通過它可以在進程間傳遞,在另一個進程中由AppWidgetHostView去獲取RemoteViews所承載的信息并且顯示出來。
AppWidgetProvider.java
這個類繼承BroadcastReceiver,并且重寫了它里面的方法,里面通常使用的是onUpdate()方法對AppWidget更新
AppWidgetManager.java
* Updates AppWidget state; gets information about installed AppWidget providers and other
* AppWidget related state.
AppWidgetHost.java
* AppWidgetHost provides the interaction with the AppWidget service for apps,
* like the home screen, that want to embed AppWidgets in their UI.
AppWidgetHostView.java
* Provides the glue to show AppWidget views. This class offers automatic animation
* between updates, and will try recycling old views for each incoming
* {@link RemoteViews}.
AppWidgetService.java
具體實現AppWidgetHost和AppWidgetManager中的方法。
對上圖的一個解釋:
當我們把一個AppWidget放在桌面的時候其實這個AppWidget是停靠在Launcher的一個View上面,被停靠的這個Activity我理解為“宿主”,而AppWidget是運行在一個獨立的進程中,所以AppWidget要與這個“宿主”通信的話就需要IPC。
當RemoteViews把AppWidget的View信息傳遞“宿主”的時候,通過AppWidgetHost獲得AppWidgetHostView的實例,這樣 按照RemoteViews中的信息將AppWidget的View繪制到“宿主”中來。至此,我們的Widget就顯示在“宿主”上了。
下圖是對AppWidgetManager
和AppWidgetHost
做的解釋,作為管理類,各自完成不同的管理任務。 在網上看到這么一段關于AppWidget的比喻,貼來大家看看
Android AppWidget框架妄析: Android中的借尸還魂
Android, AppWidget, 借尸還魂
由于初識Android不久,所以一切分析皆可有誤,故而只能為之妄析。 題目起的比較恐怖,然非我本意。 只是實在找不到更加貼切的,可以對AppWidget框架一針而見血的比喻了。 閑話少說,且看如何個借尸還魂。
首看魂者何來。 大家都知道Widget的宗旨,就是要在同一屏幕(界面上)運行多個具有獨立功能的小插件,從而豐富功能的同時簡化操作。那么,在Android的4大組件中,何人可以充當該角色,抑或需要再獨立設計一個組件? Activity? 非也!! Activity是UI呈現和用戶交互的一個組件,具有獨特的Task管理機制,同一時刻,框架只允許一個Activity與用戶交互并呈現。 而Widget的特點是,多實例的并發交互性。 所以,Activity不能滿足,不能滿足同時多個Widget的并發交互和呈現。 既然不能前臺,那么只能在后臺Running, Service or BroadCastReceiver? 由于Widget需要處理眾多的事件交互,所以,BroadCastReceiver更加合適。 既然找到了合適的,那么也就沒有必要再創造新的。 夠用就可以,不是越多越好,這也是軟件設計的準則。 OK, AppWidget的魂已經找到,BroadCastReceive也, 所以,Android中的AppWidget其本質就是一個BroadCastReceive組件。
再看尸者何來。 尸者,陽間之物也。 雖已死(本身無用),卻能見光(呈現)也。 任何一個期望在其之上運行Widget的前臺的應用(Activity),其實就是一個Widget宿主。 其本身而言,無任何Widget功能,但卻可以和用戶交互并呈現,從此點而言,可謂尸也。 Android中的AppHost即為尸也。
最后我們看如何還魂。 AppWidget為魂,功能強大,為所欲為,但卻始終位于陰間(后臺運行),無法見日,故而眾人不可觀之。 AppHost為尸,雖見天日,卻已無所可為。 我們何不將此二者互補那?? 但是,陰陽兩隔,必須使用特殊的方式, 此即為還魂術。 通過還魂術,可使得魂寄于尸而見天日。 還魂術就是陰間通往陽間的大道。 Android中的還魂術即為RemoteView。 在Android中,由于進程邊界的存在,使得AppWidget與AppHost也陰陽兩隔,默認是無法直接溝通的。 采用RemoteView,讓AppWidget將一切需要呈現的描述構建到RemoteView中,AppHost中再基于該描述,重新創建于屬于自己進程中的View進而顯示。