我有一个从api中获取数据并在db中缓存的应用程序。我希望能够在窗口小部件中显示此数据(从数据库),并添加一个按钮来更新数据,按下该按钮将获取数据并更新数据库,从而更新窗口小部件。问题是因为我使用的是mvvm,我不确定是否可以使用livedata和jetpack组件的高级支持。
所以我只是在widget update fun中创建了一个Dao参考,并获取了db。那确实获取了数据,但是它没有更新textview,我记录了它,并向我正确显示了数据。
companion object {
internal fun updateAppWidget(
context: Context, appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val db = AppDatabase.getInstance(context.applicationContext).weatherDao()
val views = RemoteViews(context.packageName, R.layout.weather_widget)
GlobalScope.launch {
val weather = db.getCurrentWeatherMetricAsync()
Log.d("TAG_TAG_TAG", "weather: " + weather.temperature);
withContext(Dispatchers.Main) {
views.setTextViewText(R.id.tv_counter, " asd " + weather.temperature)
}
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
道为此有一个悬浮的乐趣。
@Query("select * from current_weather where id = 0")
suspend fun getCurrentWeatherMetricAsync(): CurrentMetric
您能告诉我如何与数据库交互以及与应用程序存储库交互的正确方法吗?
最佳答案
由于您正在使用Room的暂停功能,因此可以在CoroutineScope
和Dispatchers.Main
(https://medium.com/androiddevelopers/room-coroutines-422b786dc4c5,https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-the-background-3e0e54d20bb)中使用它。
CoroutineScope(Dispatchers.Main.immediate).launch {
val weather = AppDatabase.getInstance(context.applicationContext).weatherDao().getCurrentWeatherMetricAsync()
val views = RemoteViews(context.packageName, R.layout.weather_widget)
views.setTextViewText(R.id.tv_counter, " asd " + weather.temperature)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
如果您不使用暂停功能甚至不使用Room,您可以使用
Dispatchers.IO
在同一线程中异步加载数据并更新RemoteView,而无需使用withContext(Dispatchers.Main)
,因为RemoteViews不是“我们的”,我们只是告诉启动程序他应该将此数据设置为on该 View 。默认情况下,这是在另一个没有UI的线程中完成的-甚至在应用创建/拥有的线程中也没有。这是我发现的唯一方法,因为
AppWidgetProvider
是BroadcastReceiver
,因此您不能在其中使用体系结构组件(https://stackoverflow.com/a/47292260/4265500)。只要您更新数据库(在JobIntentService
,Worker
(WorkManager
),Coroutines
,Wheatever中)并获得updateAppWidget()
的最新记录(就像您正在做的那样),就只需强制更新小部件即可。这是用于强制窗口小部件更新的便捷扩展功能:
fun Context.updateWidget() {
val widgetUpdateIntent = Intent(this, Widget::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
putExtra(
AppWidgetManager.EXTRA_APPWIDGET_IDS,
AppWidgetManager.getInstance(this@updateWidget).getAppWidgetIds(
ComponentName(
this@updateWidget,
Widget::class.java
)
)
)
}
sendBroadcast(widgetUpdateIntent)
}