如何观察广播接收机的流量?



我有一个使用共享首选项实现的应用程序小部件。
现在我正在把它迁移到Data Store。

这里的问题是我如何在AppWidgetProvider (BroadCastReceiver的子类)中观察/收集流数据?

重现问题的最小代码。

MyAppWidgetProvider:

class MyAppWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
}
internal fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
RemoteViews(context.packageName, R.layout.widget_layout).also { views ->
val data = loadDataFromPreferences(context, appWidgetId)
views.setTextViewText(
R.id.textview_title,
data.title
)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}

DataStoreUtil:

internal fun loadDataFromPreferences(context: Context, appWidgetId: Int): Flow<Data> {
val dataStore: DataStore<Preferences> = context.createDataStore(
name = PREFS_NAME,
migrations = listOf(SharedPreferencesMigration(context, PREFS_NAME))
)
val PREF_TITLE = stringPreferencesKey(PREF_PREFIX_KEY + appWidgetId + PREF_SUFFIX_TITLE)
return dataStore.data
.catch {
if (it is IOException) {
it.printStackTrace()
emit(emptyPreferences())
} else {
throw it
}
}
.map { preferences ->
// No type safety.
val title = preferences[PREF_TITLE] ?: ""
Data(title)
}
}

注意:

  1. Data -一个自定义模型类
  2. loadDataFromPreferences()在使用共享偏好时返回类型为Data
    val data = loadDataFromPreferences(context, appWidgetId)-由于数据类型已更改为Flow,导致updateAppWidget()错误的数据存储更改为Flow<Data>

您可以使用collectFlow获取数据

val result = loadDataFromPreferences(context, appWidgetId)
CoroutineScope(Dispatchers.Main).launch{
result.collect{ data ->
views.setTextViewText(
R.id.textview_title,
data.title
}
}

Thanks torajan kt的答案。
CoroutineScope(Dispatchers.Main).launch开始,这是解决方案的主要方面。

但是,collect()没有像预期的那样工作。用first()代替,它解决了这个问题。

在下面张贴工作代码:

MyAppWidgetProvider:

class MyAppWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
for (appWidgetId in appWidgetIds) {
CoroutineScope(Dispatchers.Main).launch {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
}
}
internal suspend fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
RemoteViews(context.packageName, R.layout.widget_layout).also { views ->
loadDataFromPreferences(context, appWidgetId)
.first {
views.setTextViewText(
R.id.textview_title,
data.title
)
appWidgetManager.updateAppWidget(appWidgetId, views)
true
}
}
}

DataStoreUtil:

internal suspend fun loadDataFromPreferences(context: Context, appWidgetId: Int): Flow<Data> {
val dataStore: DataStore<Preferences> = context.createDataStore(
name = PREFS_NAME,
migrations = listOf(SharedPreferencesMigration(context, PREFS_NAME))
)
val PREF_TITLE = stringPreferencesKey(PREF_PREFIX_KEY + appWidgetId + PREF_SUFFIX_TITLE)
return dataStore.data
.catch {
if (it is IOException) {
it.printStackTrace()
emit(emptyPreferences())
} else {
throw it
}
}
.map { preferences ->
// No type safety.
val title = preferences[PREF_TITLE] ?: ""
Data(title)
}
}

最新更新