Read The Fucking Source Code
引言
- Android AppWidget相對偏冷門。
-
開門見山一張圖,復雜問題庖解牛。
Android AppWidget 整體架構圖
1. AppWidget簡介
- Android widget 也稱為桌面插件,其是android系統應用開發層面的一部分,但是又有特殊用途,而且會成為整個android系統的亮點。Android中的AppWidget與google widget和中移動的widget并不是一個概念,這里的AppWidget只是把一個進程的控件嵌入到別外一個進程的窗口里的一種方法。
- AppWidget的服務核心在AppWidgetService中,它是系統應用,在SystemServer進程中。
- AppWidget的提供方由應用提供(對大部分應用開發者來說,了解操作這一塊就夠了)。
- AppWidget的顯示方,基本上運行在Launcher中。
- AppWidget支持的控件是由局限性的,比如不支持RecyclerView等。
- RemoteViews 在Android中的使用場景主要有:自定義通知欄和桌面小部件。
2. AppWidget提供方
2.1 XML <appwidget-provider>
- minHeight、minWidth 定義Widget的最小高度和最小寬度(Widget可以通過拉伸來調整尺寸大小)。
- previewImage 定義添加小部件時顯示的圖標。
- initialLayout 定義了小部件使用的布局。
- updatePeriodMillis 定義小部件自動更新的周期,單位為毫秒。
- resizeMode 指定了 widget 的調整尺寸的規則。可取的值有: “horizontal”, “vertical”, “none”。“horizontal"意味著widget可以水平拉伸,“vertical”意味著widget可以豎值拉伸,“none”意味著widget不能拉伸;默認值是"none”。
- widgetCategory 指定了 widget 能顯示的地方:能否顯示在 home Screen 或 lock screen 或 兩者都可以。它的取值包括:“home_screen” 和 “keyguard”。Android 4.2 引入。
2.2 AppWidgetProvider重載方法
- onUpdate()當Widget被添加或者被更新時會調用該方法。上邊我們提到通過配置updatePeriodMillis可以定期更新Widget。但是當我們在widget的配置文件中聲明了android:configure的時候,添加Widget時則不會調用onUpdate方法。
- onAppWidgetOptionsChanged()這個方法會在添加Widget或者改變Widget的大小時候被調用。在這個方法中我們還可以根據Widget的大小來選擇性的顯示或隱藏某些控件。
- onDeleted(Context, int[])當控件被刪除的時候調用該方法。
- onEnable(Context) 第一個加入到屏幕上。
- onDisabled(Context)最后一個widget從屏幕移除。
- onReceive(Context, Intent) 當接收到廣播的時候會被調用。
2.3 AppWidgetProvider的使用經驗
- 作為AppWidgetProvider的實現者,一定要實現onUpdate函數,因為這個函數決定widget的顯示方式,如果沒有這個函數widget根本沒辦法出現。
- onUpdate的實現基本上遵循下面的流程:
- 創建RemoteViews。
- 調用AppWidgetManager的updateAppWidget去更新widget。
3. AppWidget顯示方
3.1 AppWidgetHost
- AppWidgetHost 是實際控制widget的地方,大家注意,widget不是一個單獨的用戶界面程序,他必須寄生在某個程序(activity)中,這樣如果程序要支持widget寄生就要實現AppWidgetHost。
- 它的主要功能有兩個:
- 監聽來自AppWidgetService的事件。
- 另外一個功能就是創建AppWidgetHostView。
- RemoteViews不是真正的View,只是View的描述,而 AppWidgetHostView才是真正的View。這里先創建AppWidgetHostView,然后通過AppWidgetService查詢 appWidgetId對應的RemoteViews,最后把RemoteViews傳遞給AppWidgetHostView去updateAppWidget。
- AppWidgetHost和AppWidgetHostView是在框架中定義的兩個基類。應用程序可以利用這兩個類來實現自己的Host。Launcher是缺省的桌面,它是一個Host的實現者。
- AppWidgetHostView是真正的View,但它只是一個容器,用來容納實際的AppWidget的View。這個AppWidget的View是根據RemoteViews的描述來創建。
3.2 Launcher3中對widget的使用理解
- Launcher3對所有widget的遍歷是在AppWidgetManagerCompat及其子類中。
- 通過AppWidgetManager的getInstalledProvidersForProfile / getInstalledProvidersForPackage(Android版本差異),獲取到AppWidgetProviderInfo的集合。
- LauncherAppWidgetHost負責監聽更新更新和創建LauncherAppWidgetHostView。
- LauncherAppWidgetHostView擴展了AppWidgetHostView,實現了對長按事件的處理。
- LauncherAppWidgetHost擴展了AppWidgetHost,這里只是重載了onCreateView,創建LauncherAppWidgetHostView的實例。
3.3 Launcher3核心代碼
Launcher3核心代碼-按需遍歷Widget集合
Launcher3核心代碼-Widget的監聽生成
4. AppWidget服務方
4.1 服務框架
- AppWidgetService是框架的的核心類,是系統 service之一,它負責widgets的管理工作。加載,刪除,定時事件等都需要AppWidgetService的處理。開機自啟動的。
- AppWidgetService存在的目的主要是解開AppWidgetProvider和AppWidgetHost之間的耦合。如果 AppWidgetProvider和AppWidgetHost的關系固定死了,AppWidget就無法在任意進程里顯示了。而有了 AppWidgetService,AppWidgetProvider根本不需要知道自己的AppWidget在哪里顯示了。
- AppWidgetManager 負責widget視圖的實際更新以及相關管理。
5. 我對整體AppWidget的理解
AppWidgetProvider中的onUpdate()參數appWidgetIds為什么是個數組?
- 我的理解是:一個AppWidgetProvider可能被多個地方使用,可能會有幾個實例存在,數組就是對應的多個實例的存在場景,可以進行區分更新。但是一般來說,只會有一個。
AppWidget的更新過程可以說的通俗一點嗎?
- Widget更新:提供方把應用信息 + RemoteViews包裝好發給發給服務方(這些只是信息結構體,其實并不是View),顯示方監聽從服務方的回調,在回調中可以拿到這些信息結構體。
- 理解方式:雖然我們的目的是更新View,但是我們不能用更新View的思路去理解,只能用更新Data的思路去理解。
- 馬夫與馬:更新頻繁當然不好,因為雖然在應用提供方不涉及View的頻繁加載,但是在顯示方(要通過數據結構生成View),這就是系統原生為什么把AppWidget 的被動刷新頻率下限設定為半小時。就怕馬夫(提供方)趕馬(顯示方),馬累死了。
RemoteViews的理解
- RemoteViews并不是一個真正的View,它沒有實現View的接口,而只是一個用于描述View的實體。比如:創建View需要的資源ID和各個控件的事件響應方法。RemoteViews會通過進程間通信機制傳遞給AppWidgetHost。
- 現在我們可以看出,Android中的AppWidget與google widget和中移動的widget并不是一個概念,這里的AppWidget只是把一個進程的控件嵌入到別外一個進程的窗口里的一種方法。View在另 外一個進程里顯示,但事件的處理方法還是在原來的進程里。
全流程處理時序簡單說明。
- AppWidgetService啟動:SystemServer服務,開機啟動。
- AppWidgetProviderInfo獲取:AppWidgetService通過PMS針對注冊了ACTION_APPWIDGET_UPDATE("android.appwidget.action.APPWIDGET_UPDATE")的靜態廣播進行掃描查詢。
- meta-data解析:查詢到的就是AppWidget,然后從其配置的meta-data中的"appwidget-provider"對應的xml文件開始解析生成AppWidgetProviderInfo結構體。
- Launcher3獲取Widget信息:Launcher通過AppWidgetManager向AppWidgetService按需拿到所有的AppWidget信息,可以進行展示。
- Launcher3顯示Widget信息:Launcher創建AppWidgetHost,通過上面拿到的Widget信息生成對應的AppWidgetHostView進行展示。
- Launcher3更新Widget信息:AppWidgetHost創建監聽AppWidgetService的更新,進行接收回調顯示更新。
- AppWidget被動刷新:AppWidgetService會根據AppWidgetProviderInfo的配置維持一個30分鐘下限的更新時鐘,來給AppWidgetProvider來發送更新通知。
- AppWidget主動刷新:應用側可以拿到AppWidgetManager來進行主動刷新。
6. 附錄(Framework層的代碼路徑及結構)
提供方-顯示方-代碼碼路徑
服務方-代碼路徑
?
小編的博客系列
優秀博客推薦
Android官網
Android列表小部件(Widget)開發詳解
Android UI組件----AppWidget控件入門詳解
Android之AppWidget(桌面小部件)開發淺析
Android之Widget
Android中Launcher對于AppWidget處理的分析:AppWidgetHost角色
Android widget使用心得
Android Widget小組件開發(一)
android開發之widget控件突然停止更新的原因