I have created an Android Widget using Jetpack Glance, I need to update it using CoroutineWorker so I am using WorkManager for it, here is the sample code
class MyWidget : GlanceAppWidget() {
companion object {
val KEY_TOPIC = stringPreferencesKey("topic")
val KEY_QUOTE = stringPreferencesKey("quote")
}
override val sizeMode = SizeMode.Exact
// override var stateDefinition: GlanceStateDefinition<*> = PreferencesGlanceStateDefinition
override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent {
val displayText = currentState(KEY_QUOTE) ?: "Quote not found"
val topic = currentState(KEY_TOPIC) ?: ""
GlanceTheme {
Scaffold(
titleBar = {
TitleBar(startIcon = ImageProvider(R.mipmap.ic_launcher), title = "Hello")
}, backgroundColor = GlanceTheme.colors.widgetBackground
) {
Column(
modifier = GlanceModifier.background(color = Color.Red)
.padding(30.dp)
) {
Text(
text = "Display Text is $displayText && Topic is $topic",
style = TextStyle(
color = ColorProvider(
color = Color(0xFF000000)
),
fontSize = 12.sp,
fontWeight = FontWeight.Medium
),
modifier = GlanceModifier.clickable {
actionStartActivity(activity = MainActivity::class.java)
}
)
Button(
"Start Activity", onClick = actionStartActivity<MainActivity>(),
style = TextStyle(
color = ColorProvider(
color = Color(0x00FF0000)
),
fontSize = 12.sp,
fontWeight = FontWeight.Medium
),
)
}
}
}
}
}
override fun onCompositionError(
context: Context,
glanceId: GlanceId,
appWidgetId: Int,
throwable: Throwable
) {
super.onCompositionError(context, glanceId, appWidgetId, throwable)
val remoteView = RemoteViews(context.packageName, R.layout.custom_error_layout)
Log.i("errorMessageis", "${throwable.message} ${throwable.localizedMessage}")
remoteView.setTextViewText(
R.id.textview,
"${throwable.message} ${throwable.localizedMessage}"
)
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, remoteView)
}
}
@HiltWorker
class CustomWorker @AssistedInject constructor(
@Assisted val context: Context,
@Assisted workerParameters: WorkerParameters,
) : CoroutineWorker(context, workerParameters) {
override suspend fun doWork(): Result {
CoroutineScope(Dispatchers.IO).launch {
val currentTimeMillis = System.currentTimeMillis()
val date = Date(currentTimeMillis)
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val formattedDate = sdf.format(date)
val glanceIds =
GlanceAppWidgetManager(context).getGlanceIds(MyWidget::class.java)
glanceIds.forEach { id ->
updateAppWidgetState(context, id) { prefs ->
prefs[KEY_QUOTE] = currentTimeMillis.toString()
prefs[KEY_TOPIC] = formattedDate
}
MyWidget().update(context, id)
}
}
return Result.success()
}
}
Now when I try to create widget from my installed android app, it just shows the loading screen which is created from android:initialLayout="@layout/glance_default_loading_layout"
Here is the complete source code I don't see any error messages as such
I tried to run the app and it got stuck in an endless loop of starting workers when you create a widget. Apparently it was caused by the way you create WorkerFactory
or rather that it should be HiltWorkerFactory
. Refactoring MyApplication
seemingly fixed it:
@HiltAndroidApp
class MyApplication : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: HiltWorkerFactory
override val workManagerConfiguration: Configuration by lazy {
Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setWorkerFactory(workerFactory)
.build()
}
}