1. 系统开机后向AppWidgetProvider发送OnEnable, onUpdate的广播流程说明
1)AppWidgetService是运行在system_server进程, 当收到user解锁回调后,会遍历该user下的appWidget.xml文件,获取到已经在Launcher上布局的AppWidgetProvider及其下所有的Widget, Widget信息里包含AppWidgetId值。
2)然后给每个Provider发送一条onEnable广播,及onUpdate广播带有该Provider下所有AppWidgetIds信息。 最后调用到Provider里的onEnable()及onUpate()中。
3)当AppWidgetProvider收到onEnable或onUpdate时,通过AppWidgetManager接口向Launcher更新RemoteViews,开机后此时Launcher才第一次获得到要更新的对应AppWidgetHostView的消息,进行更新。
关键代码:
2. AppWidgetProvider向Launcher更新RemoteViews的执行流程
特别说明在调用到Launcher端AppWidgetHostView类中时, Launcher端更新过程:
1) 在updateAppWidget中调用applyRemoteViews, 并且第二个异步参数传入true, Android原生framework代码逻辑。
2)2)在applyRemoteViews中,运行在Launcher主线程中,
会执行mLastExecutionSignal.cancel(); 该函数会对异步的RemoteViews的action映射过程进行取消。取消上一次更新的AsyncTask执行。
3)因为采用异步方式,所以执行inflateAsync进行本次更新。
4)在此处重新赋值本次的mLastExecutionSignal对象,如果下一次更新时, 还会调用本次的cancel来取消异步task执行。
5)分析下RemoteViews里异步的执行过程:
-
在startTaskOnExecutor()中设置了cancellistener。
即当上一步调用mLastExecutionSignal.cancel()时,
onCancel()函数被执行。
-
在doInbackground执行映射每个action时, 如果判断已cancel则不再执行for循环。并且onPostExecute不会被执行。
onPostExecute的执行是在Launcher主线程, 执行中会调用AppWidgetHostView的onViewApplied() 更新view。
以上过程想说明,如果在AysncTask异步执行过程中,Post到主线程执行前,如果被cancel了,那么Launcher上Widget的view显示是不会被更新的。因此,如果AppWidgetProvider端高频率的短时间间隔调用updateAppWidget, 可能出现Launcher还未来得及加载view时,已经被下一次更新cancel掉了。这样会缺失上一次的更新view, 从而导致AppWidgetHostView中显示的remoteview与期望更新上的不同步。
以上过程都是基于AOSP O版本以后的流程,采用了异步更新方式。