android: use WorkManager to update saved posts periodically

This commit is contained in:
Harsh Shandilya 2022-04-05 23:23:55 +05:30
parent f05a90e281
commit 27a8d16487
No known key found for this signature in database
GPG key ID: 366D7BBAD1031E80
6 changed files with 105 additions and 9 deletions

View file

@ -20,6 +20,7 @@ android {
dependencies {
kapt(libs.dagger.hilt.compiler)
kapt(libs.androidx.hilt.compiler)
implementation(projects.api)
implementation(projects.common)
implementation(projects.database)
@ -30,6 +31,7 @@ dependencies {
implementation(libs.androidx.appcompat)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.hilt.work)
implementation(libs.androidx.lifecycle.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.paging.compose)
@ -39,4 +41,5 @@ dependencies {
implementation(libs.kotlin.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.retrofit.kotlinxSerializationConverter) { isTransitive = false }
implementation(libs.androidx.work.runtime.ktx)
}

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="dev.msfjarvis.claw.android">
<uses-permission android:name="android.permission.INTERNET" />
@ -56,5 +57,15 @@
android:pathPattern="/s/....../...*"/>
</intent-filter>
</activity>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>
</manifest>

View file

@ -2,10 +2,16 @@ package dev.msfjarvis.claw.android
import android.app.Application
import android.os.StrictMode
import android.util.Log
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject
@HiltAndroidApp
class ClawApplication : Application() {
class ClawApplication : Application(), Configuration.Provider {
@Inject lateinit var workerFactory: HiltWorkerFactory
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
@ -13,4 +19,11 @@ class ClawApplication : Application() {
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build())
}
}
override fun getWorkManagerConfiguration(): Configuration {
return Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setWorkerFactory(workerFactory)
.build()
}
}

View file

@ -6,10 +6,18 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.lifecycleScope
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import dagger.hilt.android.AndroidEntryPoint
import dev.msfjarvis.claw.android.ui.LobstersApp
import dev.msfjarvis.claw.android.work.SavedPostUpdaterWorker
import dev.msfjarvis.claw.common.comments.HTMLConverter
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@AndroidEntryPoint
@ -23,10 +31,26 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
installSplashScreen()
setContent {
LobstersApp(
urlLauncher = urlLauncher,
htmlConverter = htmlConverter,
) { url -> webUri = url }
LobstersApp(urlLauncher = urlLauncher, htmlConverter = htmlConverter) { url -> webUri = url }
}
lifecycleScope.launchWhenCreated {
val postUpdateWorkRequest =
PeriodicWorkRequestBuilder<SavedPostUpdaterWorker>(24, TimeUnit.HOURS)
.setConstraints(
Constraints.Builder()
.setRequiresCharging(false)
.setRequiresBatteryNotLow(true)
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresDeviceIdle(true)
.build()
)
.build()
WorkManager.getInstance(this@MainActivity)
.enqueueUniquePeriodicWork(
"updateSavedPosts",
ExistingPeriodicWorkPolicy.KEEP,
postUpdateWorkRequest,
)
}
}

View file

@ -0,0 +1,40 @@
package dev.msfjarvis.claw.android.work
import android.content.Context
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dev.msfjarvis.claw.android.viewmodel.SavedPostsRepository
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.common.posts.toDbModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
/**
* WorkManager-backed [CoroutineWorker] that gets all the posts from [SavedPostsRepository], fetches
* their newest state using the [LobstersApi] and then writes them back to the database. This allows
* saved posts that were saved before comment counts were added to be able to show a comment count
* and for new-enough posts that are still getting comments to have an accurate one.
*/
@OptIn(ExperimentalCoroutinesApi::class)
@HiltWorker
class SavedPostUpdaterWorker
@AssistedInject
constructor(
private val savedPostsRepository: SavedPostsRepository,
private val lobstersApi: LobstersApi,
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
) : CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
savedPostsRepository
.savedPosts
.first()
.mapNotNull { post -> runCatching { lobstersApi.getPostDetails(post.shortId) }.getOrNull() }
.map { postDetails -> postDetails.toDbModel() }
.map { post -> savedPostsRepository.savePost(post) }
return Result.success()
}
}