Android AppWidget

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 Framework 全家桶
?

優秀博客推薦

Android官網
Android列表小部件(Widget)開發詳解
Android UI組件----AppWidget控件入門詳解
Android之AppWidget(桌面小部件)開發淺析
Android之Widget
Android中Launcher對于AppWidget處理的分析:AppWidgetHost角色
Android widget使用心得
Android Widget小組件開發(一)
android開發之widget控件突然停止更新的原因

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容