tl;dr问题:
如何正确刷新小工具,例如,每分钟在后台发出网络请求,可靠地工作在Android 5-13,并根据政策
我有一个应用程序小部件,它需要比强制updatePeriodMillis
更频繁地刷新,还应该提供自刷新按钮。自我间隔刷新是用AlarmManager
做的,效果很好,在按钮下点击我有相同的PendingIntent
:
Intent intent = new Intent(REPORT_WIDGET_RUN_UPDATE);
intent.setClass(context, ReportAppWidgetProvider.class);
return PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
在提供商方面,onReceive
在这两种情况下都会被调用,我现在应该做一些网络工作。我使用的是Volley,所以它很琐碎,但由于context
被传递给onReceive
,我总是会超时。。。
几年前,我已经开始为此使用Service
,但启动Android 8ForegroundService
必须用于这种情况(后台工作,不运行任何Activity
(。我不想展示";"自动消失";通知,所以我切换到了JobIntentService
。它有一些令人讨厌的罕见错误,现在已经被弃用了,所以即使它运行得很好,我也决定转到WorkManager
,作为链接下的最后一篇文章,以及官方文档或一些文章(例如本文(。
所以现在我的JobIntentService
变成了Worker
,接下来是这篇文章,工人建设者中的Context
与Volley合作,完成了网络连接,将反馈广播发送给提供商和。。。在整个操作之后,我得到了一个非常不需要的系统,名为android.appwidget.action.APPWIDGET_UPDATE
。这不是我的行为,它打断了我的心!
在Android 13中,我在系统日志中看到了一些建议,为什么我会得到这个调用
I/LauncherAppWidgetHostView: App widget created with id: 33
I/LauncherAppWidgetHostView: App widget with id: 33 loaded
所以我的小部件在这样的刷新操作之后;重新创建";。。。行为在Android 10上完全相同,但没有以上/任何日志(不同的启动器(
我的问题是:如何在后台正确刷新具有网络请求的小工具,可靠地工作在Android 5-13并根据政策?
也许我应该坚持有时出现ForegroundService
作为开始13,它无论如何都会被隐藏?据我所知,不显示通知有几秒钟的限制?对我来说,进行网络调用,然后向appwidget提供商广播响应就足够了(调用时抛出3-4秒超时(。任何建议,最好是工作实例赞赏
我的猜测是,您遇到了已知的WorkManager
问题;重新启动";您的小工具。我最初不知道是什么原因导致了这一点,但谷歌的问题跟踪器上报告了几个问题,包括我提交的这个问题。解决这个问题的方法是
创建一个一次性Worker,设置为10年后,(使用setInitialDelay(并对其设置至少一个约束
你可以在这里看到我答案中的代码
用以下代码修复,非常感谢用户496854的回答和源
public class ReportAppWidgetProvider extends AppWidgetProvider {
...
@Override
public void onReceive(Context context, final Intent intent) {
super.onReceive(context, intent);
Log.i(ReportAppWidgetProvider.this.getClass().getSimpleName(),
"onReceive action " + intent.getAction());
setUpDummyWorkerForPreventingAppWidgetRestarts(context);
...
}
// https://issuetracker.google.com/issues/241076154
private void setUpDummyWorkerForPreventingAppWidgetRestarts(Context context) {
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(AppWidgetDelayedWidgetWorker.class)
.setInitialDelay(10 * 365, TimeUnit.DAYS)
.setConstraints(
new Constraints.Builder()
.setRequiresCharging(true)
.build()
)
.build();
WorkManager.getInstance(context).enqueueUniqueWork(
AppWidgetDelayedWidgetWorker.TAG,
ExistingWorkPolicy.REPLACE,
work);
}
我用CCD_ 18只保留了一个";"无限实例";,因为每次广播都调用我的方法只是为了进行shure(事实上,有两个工人和多个操作由他们处理(
有趣的事实:上面的部分是Java,下面是Kotlin。时间标记:(
class AppWidgetDelayedWidgetWorker(
appContext: Context,
workerParams: WorkerParameters,
) : CoroutineWorker(appContext, workerParams) {
companion object {
const val TAG = "DummyWorker"
}
override suspend fun doWork(): Result {
Log.i("DummyWorker", "doWork")
return Result.success()
}
}