0

我有一个使用共享首选项实现的应用小部件。
现在我正在将其迁移到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)
    }
}

数据存储工具:

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. 数据 - 自定义模型类
  2. loadDataFromPreferences() 返回类型是Data使用共享首选项时。将其更改Flow<Data>为 DataStore,这会导致updateAppWidget()行中的错误:
    val data = loadDataFromPreferences(context, appWidgetId)- 因为数据类型已更改为 Flow。
4

2 回答 2

3

您可以使用collectFlow

val result = loadDataFromPreferences(context, appWidgetId)
CoroutineScope(Dispatchers.Main).launch{
   result.collect{ data ->
       views.setTextViewText(
            R.id.textview_title,
            data.title
   }
}
于 2021-01-21T08:51:07.670 回答
0

感谢rajan 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
            }
    }
}

数据存储工具:

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)
        }
}
于 2021-01-22T10:54:03.500 回答