AppWidgetProvider.onRestored()调用时机、重写场景及相关疑问
咱们一步步拆解你提出的这些问题:
1. 请问AppWidgetProvider.onRestored()的具体调用时机是什么?
这个方法的触发逻辑很明确:当你的AppWidget实例通过系统备份被恢复时,系统会发送AppWidgetManager.ACTION_APPWIDGET_RESTORED广播,onRestored()就是专门响应这个广播的回调方法。而且要注意,它执行完成后会立刻调用onUpdate(),让你能马上为恢复后的Widget生成对应的RemoteViews,确保Widget能正常显示。
2. 哪些场景下需要重写onRestored()?它仅对应清单文件中可启用/禁用的备份功能吗?
你需要重写onRestored()的核心场景是:你的AppWidget维护了和特定AppWidgetId绑定的持久化数据——比如你在SharedPreferences、本地数据库里存了某个WidgetId对应的自定义配置、状态信息(比如用户设置的Widget显示内容、刷新频率)。
因为当Widget从备份恢复时,系统会给恢复后的Widget分配全新的AppWidgetId,这时候你必须把旧Id对应的所有数据映射到新Id上,不然你的Widget加载出来就会用错数据,甚至直接显示异常。
它确实是专门对应系统备份恢复功能的,也就是你在App清单中配置的android:allowBackup相关开关控制的功能。只有当通过系统官方的备份流程恢复Widget实例时,这个方法才会被触发。
3. 应用更新时该方法是否会被调用?或者在AppWidgetIds可能发生变化的其他场景下会触发?
应用更新的时候这个方法完全不会被调用,因为应用更新过程中,已存在的WidgetId不会发生任何变化——系统不会因为你更新了App就给现有Widget重新分配Id。
至于其他可能导致WidgetId变化的场景,目前只有系统备份恢复Widget这一种情况会触发onRestored()。比如用户换了新手机,通过备份恢复了旧手机上的Widget;或者在同一台手机上重置系统后恢复备份,这时候WidgetId会被重新分配,才会触发这个回调。像用户手动添加/删除Widget、Widget因内存不足被重启这类场景,都不会触发它。
4. 我认为WidgetID应永久不变,但不同厂商/启动器对Widget的处理方式不同,该方法能否用于解决幽灵Widget问题?
首先得澄清:正常情况下AppWidgetId确实是永久绑定到对应的Widget实例的,但部分厂商的定制启动器可能在一些特殊操作(比如清理启动器缓存、非系统备份的恢复操作)下出现WidgetId异常变化的情况,但这种场景下onRestored()是不会被触发的——因为它只响应系统官方备份恢复的广播。
所以onRestored()没法解决幽灵Widget问题。幽灵Widget(比如启动器上显示空白Widget、已删除的Widget残留显示)的成因通常是启动器和你的AppWidgetProvider之间的状态同步异常,或者Widget的RemoteViews加载失败、生命周期处理不当。要解决这类问题,你可能需要从onUpdate()、onAppWidgetOptionsChanged()这些核心回调入手优化状态维护,或者在Widget的配置页面增加状态校验逻辑,而非依赖onRestored()。
官方方法注释参考
/**
- 当此AppWidget提供者的实例从备份中恢复时,响应{@link AppWidgetManager#ACTION_APPWIDGET_RESTORED}广播而调用。
- 如果您的提供者维护了Widget实例的任何持久化数据,请重写此方法以将旧的AppWidgetIds重新映射到新值,并更新任何相关的应用状态。
此回调后会立即调用{@link #onUpdate},以便您的提供者可以立即为新恢复的实例生成合适的RemoteViews。
- {@more}
- @param context
- @param oldWidgetIds
- @param newWidgetIds
*/
public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) { }
内容的提问来源于stack exchange,提问作者einUsername

