Jus*_*tin 30 multithreading android widget background-process android-8.0-oreo
假设我有一个将targetSDKVersion设置为26的应用程序的小部件.此小部件需要100毫秒到10秒才能更新.大部分时间都在1s以下.在Android O之前,如果在我的AppWidgetProvider上调用了onUpdate(),我可以启动后台服务来更新这个小部件.但是,如果您尝试该行为,Android O将返回IllegalStateException.启动前台服务的显而易见的解决方案似乎是一种极端的措施,可以在99%的时间内在10秒以内完成.
可能的解决方案
我个人并不喜欢上述任何一种解决方案.希望我错过了一些东西.
(更令人沮丧的是,我的应用程序已经被系统调用onUpdate()加载到内存中.我没有看到如何将我的应用程序加载到内存中以调用onUpdate(),但后来没有给我的应用程序1s更新小部件UI线程正在为任何人节省电池寿命.)
Com*_*are 10
您没有指出更新触发机制是什么.您似乎担心延迟("您的小部件可能会或可能不会在一段时间内更新"),因此我将假设您的关注与用户与应用小部件的交互相关联,例如点击按钮.
使用JobScheduler尽快安排作业.您的小部件可能会或可能不会更新一段时间.
这是"使用JobIntentService" 的变体,AFAIK是此类场景的推荐解决方案.
其他选择包括:
使用getForegroundService()带PendingIntent.有了这个,你有效地"粉红色发誓"你的服务将startForeground()在ANR时间范围内调用.如果工作时间超过几秒钟,请致电startForeground()以确保Android不会变得暴躁.这应该最小化前景通知出现的时间.而且,如果用户点击了一个按钮并且您在几秒钟后仍然忙于工作,您可能希望显示通知或以其他方式做某事让用户知道他们要求的内容仍在进行中.
使用goAsync()on BroadcastReceiver,在接收器的上下文中工作而不占用主应用程序线程.我没有尝试使用Android 8.0+,所以YMMV.
您可以使用WorkManager更新小部件。在具有 API 14+ 的设备上使用 WorkManager。您需要像这样重写 fun onReceive(context: Context?,intent: Intent?) :
val ACTION_AUTO_UPDATE : String = "AUTO_UPDATE";
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent)
if(intent?.action.equals(ACTION_AUTO_UPDATE))
{
val appWidgetManager = AppWidgetManager.getInstance(context)
val thisAppWidgetComponentName = ComponentName(context!!.getPackageName(), javaClass.name)
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidgetComponentName)
for (appWidgetId in appWidgetIds) {
// update widget
}
}
}
Run Code Online (Sandbox Code Playgroud)
您应该创建PeriodicWorkRequest。您必须用于重复工作。定期工作的最小间隔为 15 分钟。当小部件启用时,我们将 periodicalWork 排入队列:
override fun onEnabled(context: Context) {
val periodicWorkRequest = PeriodicWorkRequest.Builder(YourWorker::class.java, 15, TimeUnit.MINUTES).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork("YourWorker", ExistingPeriodicWorkPolicy.REPLACE,periodicWorkRequest)
}
Run Code Online (Sandbox Code Playgroud)
并在小部件禁用时取消它:
override fun onDisabled(context: Context) {
WorkManager.getInstance(context).cancelAllWork()
}
Run Code Online (Sandbox Code Playgroud)
最后我们创建工人阶级:
class YourWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
var context : Context? = null
init {
context = ctx
}
override fun doWork(): Result {
val alarmIntent = Intent(context, YourWidget::class.java)
alarmIntent.action = YourWidget().ACTION_AUTO_UPDATE
context?.sendBroadcast(alarmIntent)
return Result.success()
}
Run Code Online (Sandbox Code Playgroud)
如果你想使用 WorkerManager,你可以添加到 build.gradle 实现 'androidx.work:work-runtime:2.3.1'
您可以在此处找到示例。
| 归档时间: |
|
| 查看次数: |
4812 次 |
| 最近记录: |