使用RemoteView按钮刷新具有网络请求的AppWidget



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()
}
}

相关内容

  • 没有找到相关文章

最新更新