Read The Fucking Source Code
引言
- Android AppWidget相對偏冷門垒在。
-
開門見山一張圖梦湘,復雜問題庖解牛。
1. AppWidget簡介
- Android widget 也稱為桌面插件能耻,其是android系統(tǒng)應用開發(fā)層面的一部分合砂,但是又有特殊用途,而且會成為整個android系統(tǒng)的亮點锯七。Android中的AppWidget與google widget和中移動的widget并不是一個概念链快,這里的AppWidget只是把一個進程的控件嵌入到別外一個進程的窗口里的一種方法。
- AppWidget的服務核心在AppWidgetService中眉尸,它是系統(tǒng)應用域蜗,在SystemServer進程中巨双。
- AppWidget的提供方由應用提供(對大部分應用開發(fā)者來說,了解操作這一塊就夠了)霉祸。
- AppWidget的顯示方筑累,基本上運行在Launcher中。
- AppWidget支持的控件是由局限性的丝蹭,比如不支持RecyclerView等慢宗。
- RemoteViews 在Android中的使用場景主要有:自定義通知欄和桌面小部件。
2. AppWidget提供方
2.1 XML <appwidget-provider>
- minHeight半夷、minWidth 定義Widget的最小高度和最小寬度(Widget可以通過拉伸來調(diào)整尺寸大衅爬取)。
- previewImage 定義添加小部件時顯示的圖標巫橄。
- initialLayout 定義了小部件使用的布局淘邻。
- updatePeriodMillis 定義小部件自動更新的周期,單位為毫秒湘换。
- resizeMode 指定了 widget 的調(diào)整尺寸的規(guī)則宾舅。可取的值有: “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被添加或者被更新時會調(diào)用該方法们妥。上邊我們提到通過配置updatePeriodMillis可以定期更新Widget猜扮。但是當我們在widget的配置文件中聲明了android:configure的時候,添加Widget時則不會調(diào)用onUpdate方法监婶。
- onAppWidgetOptionsChanged()這個方法會在添加Widget或者改變Widget的大小時候被調(diào)用旅赢。在這個方法中我們還可以根據(jù)Widget的大小來選擇性的顯示或隱藏某些控件。
- onDeleted(Context, int[])當控件被刪除的時候調(diào)用該方法惑惶。
- onEnable(Context) 第一個加入到屏幕上煮盼。
- onDisabled(Context)最后一個widget從屏幕移除。
- onReceive(Context, Intent) 當接收到廣播的時候會被調(diào)用带污。
2.3 AppWidgetProvider的使用經(jīng)驗
- 作為AppWidgetProvider的實現(xiàn)者僵控,一定要實現(xiàn)onUpdate函數(shù),因為這個函數(shù)決定widget的顯示方式刮刑,如果沒有這個函數(shù)widget根本沒辦法出現(xiàn)喉祭。
- onUpdate的實現(xiàn)基本上遵循下面的流程:
- 創(chuàng)建RemoteViews养渴。
- 調(diào)用AppWidgetManager的updateAppWidget去更新widget。
3. AppWidget顯示方
3.1 AppWidgetHost
- AppWidgetHost 是實際控制widget的地方泛烙,大家注意理卑,widget不是一個單獨的用戶界面程序,他必須寄生在某個程序(activity)中蔽氨,這樣如果程序要支持widget寄生就要實現(xiàn)AppWidgetHost藐唠。
- 它的主要功能有兩個:
- 監(jiān)聽來自AppWidgetService的事件。
- 另外一個功能就是創(chuàng)建AppWidgetHostView鹉究。
- RemoteViews不是真正的View宇立,只是View的描述,而 AppWidgetHostView才是真正的View自赔。這里先創(chuàng)建AppWidgetHostView妈嘹,然后通過AppWidgetService查詢 appWidgetId對應的RemoteViews,最后把RemoteViews傳遞給AppWidgetHostView去updateAppWidget绍妨。
- AppWidgetHost和AppWidgetHostView是在框架中定義的兩個基類润脸。應用程序可以利用這兩個類來實現(xiàn)自己的Host。Launcher是缺省的桌面他去,它是一個Host的實現(xiàn)者毙驯。
- AppWidgetHostView是真正的View,但它只是一個容器灾测,用來容納實際的AppWidget的View爆价。這個AppWidget的View是根據(jù)RemoteViews的描述來創(chuàng)建。
3.2 Launcher3中對widget的使用理解
- Launcher3對所有widget的遍歷是在AppWidgetManagerCompat及其子類中媳搪。
- 通過AppWidgetManager的getInstalledProvidersForProfile / getInstalledProvidersForPackage(Android版本差異)铭段,獲取到AppWidgetProviderInfo的集合。
- LauncherAppWidgetHost負責監(jiān)聽更新更新和創(chuàng)建LauncherAppWidgetHostView蛾号。
- LauncherAppWidgetHostView擴展了AppWidgetHostView稠项,實現(xiàn)了對長按事件的處理涯雅。
- LauncherAppWidgetHost擴展了AppWidgetHost鲜结,這里只是重載了onCreateView,創(chuàng)建LauncherAppWidgetHostView的實例活逆。
3.3 Launcher3核心代碼
4. AppWidget服務方
4.1 服務框架
- AppWidgetService是框架的的核心類精刷,是系統(tǒng) service之一,它負責widgets的管理工作蔗候。加載怒允,刪除,定時事件等都需要AppWidgetService的處理锈遥。開機自啟動的纫事。
- AppWidgetService存在的目的主要是解開AppWidgetProvider和AppWidgetHost之間的耦合勘畔。如果 AppWidgetProvider和AppWidgetHost的關系固定死了,AppWidget就無法在任意進程里顯示了丽惶。而有了 AppWidgetService炫七,AppWidgetProvider根本不需要知道自己的AppWidget在哪里顯示了。
- AppWidgetManager 負責widget視圖的實際更新以及相關管理钾唬。
5. 我對整體AppWidget的理解
AppWidgetProvider中的onUpdate()參數(shù)appWidgetIds為什么是個數(shù)組?
- 我的理解是:一個AppWidgetProvider可能被多個地方使用万哪,可能會有幾個實例存在,數(shù)組就是對應的多個實例的存在場景抡秆,可以進行區(qū)分更新奕巍。但是一般來說,只會有一個儒士。
AppWidget的更新過程可以說的通俗一點嗎的止?
- Widget更新:提供方把應用信息 + RemoteViews包裝好發(fā)給發(fā)給服務方(這些只是信息結(jié)構(gòu)體,其實并不是View)着撩,顯示方監(jiān)聽從服務方的回調(diào)冲杀,在回調(diào)中可以拿到這些信息結(jié)構(gòu)體。
- 理解方式:雖然我們的目的是更新View睹酌,但是我們不能用更新View的思路去理解权谁,只能用更新Data的思路去理解。
- 馬夫與馬:更新頻繁當然不好憋沿,因為雖然在應用提供方不涉及View的頻繁加載旺芽,但是在顯示方(要通過數(shù)據(jù)結(jié)構(gòu)生成View),這就是系統(tǒng)原生為什么把AppWidget 的被動刷新頻率下限設定為半小時辐啄。就怕馬夫(提供方)趕馬(顯示方)采章,馬累死了。
RemoteViews的理解
- RemoteViews并不是一個真正的View壶辜,它沒有實現(xiàn)View的接口悯舟,而只是一個用于描述View的實體。比如:創(chuàng)建View需要的資源ID和各個控件的事件響應方法砸民。RemoteViews會通過進程間通信機制傳遞給AppWidgetHost抵怎。
- 現(xiàn)在我們可以看出,Android中的AppWidget與google widget和中移動的widget并不是一個概念岭参,這里的AppWidget只是把一個進程的控件嵌入到別外一個進程的窗口里的一種方法反惕。View在另 外一個進程里顯示,但事件的處理方法還是在原來的進程里演侯。
全流程處理時序簡單說明姿染。
- AppWidgetService啟動:SystemServer服務,開機啟動秒际。
- AppWidgetProviderInfo獲取:AppWidgetService通過PMS針對注冊了ACTION_APPWIDGET_UPDATE("android.appwidget.action.APPWIDGET_UPDATE")的靜態(tài)廣播進行掃描查詢悬赏。
- meta-data解析:查詢到的就是AppWidget狡汉,然后從其配置的meta-data中的"appwidget-provider"對應的xml文件開始解析生成AppWidgetProviderInfo結(jié)構(gòu)體。
- Launcher3獲取Widget信息:Launcher通過AppWidgetManager向AppWidgetService按需拿到所有的AppWidget信息,可以進行展示闽颇。
- Launcher3顯示W(wǎng)idget信息:Launcher創(chuàng)建AppWidgetHost轴猎,通過上面拿到的Widget信息生成對應的AppWidgetHostView進行展示。
- Launcher3更新Widget信息:AppWidgetHost創(chuàng)建監(jiān)聽AppWidgetService的更新进萄,進行接收回調(diào)顯示更新捻脖。
- AppWidget被動刷新:AppWidgetService會根據(jù)AppWidgetProviderInfo的配置維持一個30分鐘下限的更新時鐘,來給AppWidgetProvider來發(fā)送更新通知中鼠。
- AppWidget主動刷新:應用側(cè)可以拿到AppWidgetManager來進行主動刷新可婶。
6. 附錄(Framework層的代碼路徑及結(jié)構(gòu))
?
小編的博客系列
優(yōu)秀博客推薦
Android官網(wǎng)
Android列表小部件(Widget)開發(fā)詳解
Android UI組件----AppWidget控件入門詳解
Android之AppWidget(桌面小部件)開發(fā)淺析
Android之Widget
Android中Launcher對于AppWidget處理的分析:AppWidgetHost角色
Android widget使用心得
Android Widget小組件開發(fā)(一)
android開發(fā)之widget控件突然停止更新的原因