如何在广播接收器中观察流量?

问题描述

我有一个使用共享首选项实现的应用小部件。
现在我正在努力将其迁移到 Data Store

这里的问题是如何观察/收集 appwidgetproviderbroadCastReceiver 的子类)中的 Flow 数据?

重现问题的最少代码

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,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。将其更改为 Flow<Data> for DataStore 导致 updateAppWidget() 行中的错误
    val data = loadDataFromPreferences(context,appWidgetId) - 因为数据类型已更改为 Flow。

解决方法

您可以使用 collectFlow 获取数据

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

感谢 rajan kt 的回答。
for train,test in kfold.split(inputs,targets): # Define callbacks checkpoint_path = f'/content/drive/MyDrive/Colab Notebooks/saveModel/Model 1/{fold_no}' os.mkdir(checkpoint_path) keras_callbacks = [ ModelCheckpoint(checkpoint_path,monitor='val_loss',save_best_only=True,mode='min') ] x_t,x_ts = inputs[train],targets[test] y_t,y_ts = inputs[train],targets[test] model_history = model.fit( train_generator,epochs=EPOCHS,verbose=1,steps_per_epoch=steps_per_epoch,validation_data=valid_generator,validation_steps=val_steps_per_epoch,callbacks=keras_callbacks).history 开始,这是解决方案的主要方面。

但是,CoroutineScope(Dispatchers.Main).launch 没有按预期工作。改用 collect() 尝试解决了问题。

在下面发布工作代码:

MyAppWidgetProvider:

first()

DataStoreUtil:

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,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
            }
    }
}