基于原生Android 13 & Launcher3,簡單梳理下widget的添加和更新過程中的核心流程。
一、Widget介紹
1.1 定義:應用微件或者小組件,是可以嵌入其他應用(如主屏幕)并接收定期更新的微型應用視圖。
1.2 使用:https://developer.android.com/develop/ui/views/appwidgets/overview?hl=zh-cn
二、整體流程概覽
App包裝的視圖信息傳遞給Launcher上添加展示。
三、代碼分析
3.1 widget相關核心類介紹
Launcher:
- android.appwidget.AppWidgetHost: launcher上管理widget的類,主要負責更新和展示的管理;
- android.appwidget.AppWidgetHostView:widget在launcher真正顯示的View;
App:
- android.appwidget.AppWidgetProvider: 本身是個廣播接收者,由它封裝事件處理和widget定義;
- android.appwidget.AppWidgetProviderInfo: appwidget-provider配置參數封裝;
System:
- android.widget.RemoteViews : 一個Parcelable,封裝視圖信息傳遞給launcher展示;
- com.android.server.appwidget.AppWidgetService: 管理widget的系統服務;
3.2 AppWidgetService系統服務
AppWidgetService 在SystemServer#startOtherServices中被初始化。對應實現類AppWidgetServiceImpl,它是widget管理的server端。
3.3 Launcher3 新添加widget流程
這里只關注3個部分:
- widget相關初始化;
- 長按拖拽widget添加到桌面流程;
- 添加widget后的廣播發起及定時任務設置。
1)widget相關初始化核心流程
創建AppWidgetHost,同時通過它創建AppWidgetHostView,AppWidgetHost通過綁定AppWidgetService實現Widget管理。
2)長按拖拽widget添加到桌面核心流程
launcher3手動拖拽添加widget整個流程都是基于QuickstepLauncher這個Activity內部處理的,它的父類是Launcher。添加widget到桌面主要做了兩個事:將id和view關聯起來,同時添加View到桌面。用戶在移動到對應位置放開手指后,會觸發view的onDrop方法,此時真正觸發view顯示。
3)添加完成后的廣播發起及定時任務設置
AppWidgetService的實現是基于AppWidgetServiceImpl實現的,綁定過程會發送enable和update廣播,同時設置一個非精準類型的Alarm定時任務。
注:AlarmManager#setInexactRepeating 非準確的輪詢。系統可以根據設備電量、CPU利用率等情況,適度推遲或提前鬧鐘執行時間。這樣可以避免在設備處于非活躍狀態時過度消耗電量
這里順帶梳理下widget相關廣播的觸發條件及設置定時任務的觸發鏈路:
觸發條件:
廣播
觸發條件
廣播 | 觸發條件 |
---|---|
ACTION_APPWIDGET_ENABLE_AND_UPDATE | 1)添加widget觸發(可發送合并廣播);2)手機啟動觸發 |
ACTION_APPWIDGET_ENABLED | 1)添加widget觸發(不可發送合并廣播,enable和update就分開發);2)手機啟動觸發 |
ACTION_APPWIDGET_UPDATE | 1)添加widget觸發 ;2)手機啟動觸發 均會加入AlarmManager輪詢后續定時觸發。 |
ACTION_APPWIDGET_OPTIONS_CHANGED | 1)widget的大小、布局、字體等參數發生變化觸發 |
ACTION_APPWIDGET_RESTORED | 1)重新啟用widget時觸發 |
ACTION_APPWIDGET_DISABLED | 1)刪除widget時觸發;2)禁用widget時觸發 |
ACTION_APPWIDGET_DELETED | 1)刪除widget時觸發 |
設置定時任務的觸發鏈路:
3.4 Alarm定時更新widget分析
發送廣播主要有場景的主動觸發和定時任務的輪詢觸發兩種,主動觸發的前面場景條件已經總結,這里主要分析輪詢任務觸發,目的是想知道非精確設置的定時任務觸發受哪些因素影響。
1)Alarm相關的核心類關系
2)設置定時任務的主要流程:
① 添加任務 + 設置定時
② 定時回調執行
整體流程總結:
- 構建Alarm: AlarmManager#setInexactRepeating發起,層層條件判斷賦值參數,最終構建Alarm,內部封裝定時任務相關信息;
- 調整觸發時間:基于Idle相關策略,包括電量、應用待機、計數器重置,來最終決定Alarm的觸發時機;
- 向內核發起一次定時設置,并wait等待;
- 定時觸發后,調度選擇對應的Alarm,執行其PendingIntent send。
3)Alarm觸發時間計算規則
com.android.server.alarm.AlarmManagerService#setImplLocked(com.android.server.alarm.Alarm)
主要受三套規則影響:
- adjustDeliveryTimeBasedOnBatterySaver(a);(電量)
- adjustDeliveryTimeBasedOnBucketLocked(a);(待機存儲桶)
- adjustDeliveryTimeBasedOnTareLocked(a);(電池管理系統)
Alarm非精準定時任務觸發流程分析:
添加widget后,launcher實現的定時器是非精確的,系統會根據電池使用情況、應用使用頻率等因素,在一個合理的時間窗口內觸發鬧鐘。當然具體觸發規則各大廠商估計都會有不同程度魔改,這里僅分析了原生策略。
3.5 Widget刷新UI流程
app收到更新廣播后,通過AppWidgetManager發起更新操作,經由系統服務去更新Launcher上對應的View。
好文推薦:
墨香帶你學Launcher
Android launcher全面剖析
Android10/11 原生Launcher3動態顯示Widget