Glance App Widget state not saved inside CoroutineWorker

1k Views Asked by At

I want to update my Glance App Widget state inside CoroutineWorker:

class MyWorker(appContext: Context, workerParams: WorkerParameters) :
    CoroutineWorker(appContext, workerParams) {

    override suspend fun doWork(): Result {
        val glanceId = GlanceAppWidgetManager(applicationContext).getGlanceIds(MyWidget::class.java).first()

        updateAppWidgetState(
            context = applicationContext,
            glanceId = glanceId,
        ) { preferences ->
            preferences.toMutablePreferences().apply{
                this[stringPreferencesKey(TASK_ID)] = id.toString()
            }
        }
            
        MyWidget().updateAll(applicationContext)
        return Result.success()
    }
}

This worker ends with success, but widget state is not updated.

class MyWidget : GlanceAppWidget() {

    override val stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition

    @Composable
    override fun Content() {
        val context = LocalContext.current
        val preferences = currentState<Preferences>()

        val taskId = preferences[stringPreferencesKey(TASK_ID)]
        if (taskId.isNullOrEmpty()) {
            val myWorker = OneTimeWorkRequestBuilder<MyWorker>().build()
            WorkManager.getInstance(context).enqueue(myWorker)

            LoadingScreen()
            return
        }

        // handle finished worker
    }

    @Composable
    fun LoadingScreen() {
        // compose loading screen
    }
}

I tested this code with single widget and it always shows loading screen and taskId is always null even though workers run successfully. How to fix this problem?

1

There are 1 best solutions below

2
Alexey Peschany On

So, the problem is in the toMutablePreferences, all of the examples I've seen used this method, however instead of saving new values to the same data store it creates a copy of data store which is not saved.

The correct code should be:

        updateAppWidgetState(
            context = applicationContext,
            glanceId = glanceId,
        ) { preferences ->
            preferences.apply{
                this[stringPreferencesKey(TASK_ID)] = id.toString()
            }
        }