refactor: Use androidx.startup for startup activities (#762)
Move initialisation of WorkManager and Timber in to new `Initializer` classes, managed by `androidx.startup`. There's a false-positive `BadConfigurationProvider` lint message because the `Configuration.Provider` is in the content provider and not the application class.
This commit is contained in:
parent
b373ee9ffe
commit
bd6bc95b01
|
@ -73,6 +73,13 @@
|
|||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="BadConfigurationProvider"
|
||||
message="Expected Application subtype to implement Configuration.Provider">
|
||||
<location
|
||||
file="src/main/java/app/pachli/PachliApplication.kt"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="SelectedPhotoAccess"
|
||||
message="Your app is currently not handling Selected Photos Access introduced in Android 14+"
|
||||
|
|
|
@ -218,8 +218,22 @@
|
|||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
tools:node="remove" />
|
||||
android:exported="false"
|
||||
tools:node="merge">
|
||||
|
||||
<meta-data
|
||||
android:name="app.pachli.initializer.DependencyGraphInitializer"
|
||||
android:value="androidx.startup" />
|
||||
<meta-data
|
||||
android:name="app.pachli.initializer.TimberInitializer"
|
||||
android:value="androidx.startup" />
|
||||
<meta-data
|
||||
android:name="app.pachli.initializer.WorkManagerInitializer"
|
||||
android:value="androidx.startup" />
|
||||
<meta-data
|
||||
android:name="androidx.work.WorkManagerInitializer"
|
||||
android:value="androidx.startup"
|
||||
tools:node="remove" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -19,14 +19,11 @@ package app.pachli
|
|||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.hilt.work.HiltWorkerFactory
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import app.pachli.components.notifications.createWorkerNotificationChannel
|
||||
import app.pachli.core.activity.LogEntryTree
|
||||
import app.pachli.core.activity.TreeRing
|
||||
import app.pachli.core.activity.initCrashReporter
|
||||
import app.pachli.core.preferences.AppTheme
|
||||
import app.pachli.core.preferences.NEW_INSTALL_SCHEMA_VERSION
|
||||
|
@ -50,18 +47,12 @@ import timber.log.Timber
|
|||
|
||||
@HiltAndroidApp
|
||||
class PachliApplication : Application() {
|
||||
@Inject
|
||||
lateinit var workerFactory: HiltWorkerFactory
|
||||
|
||||
@Inject
|
||||
lateinit var localeManager: LocaleManager
|
||||
|
||||
@Inject
|
||||
lateinit var sharedPreferencesRepository: SharedPreferencesRepository
|
||||
|
||||
@Inject
|
||||
lateinit var logEntryTree: LogEntryTree
|
||||
|
||||
override fun attachBaseContext(base: Context?) {
|
||||
super.attachBaseContext(base)
|
||||
|
||||
|
@ -83,12 +74,6 @@ class PachliApplication : Application() {
|
|||
|
||||
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
||||
|
||||
when {
|
||||
BuildConfig.DEBUG -> Timber.plant(Timber.DebugTree())
|
||||
BuildConfig.FLAVOR_color == "orange" -> Timber.plant(TreeRing)
|
||||
}
|
||||
Timber.plant(logEntryTree)
|
||||
|
||||
// Migrate shared preference keys and defaults from version to version.
|
||||
val oldVersion = sharedPreferencesRepository.getInt(PrefKeys.SCHEMA_VERSION, NEW_INSTALL_SCHEMA_VERSION)
|
||||
if (oldVersion != SCHEMA_VERSION) {
|
||||
|
@ -108,12 +93,8 @@ class PachliApplication : Application() {
|
|||
|
||||
createWorkerNotificationChannel(this)
|
||||
|
||||
WorkManager.initialize(
|
||||
this,
|
||||
androidx.work.Configuration.Builder().setWorkerFactory(workerFactory).build(),
|
||||
)
|
||||
|
||||
val workManager = WorkManager.getInstance(this)
|
||||
|
||||
// Prune the database every ~ 12 hours when the device is idle.
|
||||
val pruneCacheWorker = PeriodicWorkRequestBuilder<PruneCacheWorker>(12, TimeUnit.HOURS)
|
||||
.setConstraints(Constraints.Builder().setRequiresDeviceIdle(true).build())
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.di
|
||||
|
||||
import android.content.Context
|
||||
import app.pachli.initializer.TimberInitializer
|
||||
import app.pachli.initializer.WorkManagerInitializer
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
/**
|
||||
* Entry point that allows [androidx.startup.Initializer] implementations
|
||||
* to inject their dependencies.
|
||||
*/
|
||||
@EntryPoint
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface InitializerEntryPoint {
|
||||
fun inject(timberInitializer: TimberInitializer)
|
||||
fun inject(workManagerInitializer: WorkManagerInitializer)
|
||||
|
||||
companion object {
|
||||
fun resolve(context: Context): InitializerEntryPoint {
|
||||
val appContext = context.applicationContext ?: throw IllegalStateException()
|
||||
return EntryPointAccessors.fromApplication(
|
||||
appContext,
|
||||
InitializerEntryPoint::class.java,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.initializer
|
||||
|
||||
import android.content.Context
|
||||
import androidx.startup.Initializer
|
||||
import app.pachli.di.InitializerEntryPoint
|
||||
|
||||
/** Empty root initializer other initialisers can depend on. */
|
||||
class DependencyGraphInitializer : Initializer<Unit> {
|
||||
override fun create(context: Context) {
|
||||
InitializerEntryPoint.resolve(context)
|
||||
}
|
||||
|
||||
override fun dependencies(): List<Class<out Initializer<*>>> {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.initializer
|
||||
|
||||
import android.content.Context
|
||||
import androidx.startup.Initializer
|
||||
import app.pachli.BuildConfig
|
||||
import app.pachli.core.activity.LogEntryTree
|
||||
import app.pachli.core.activity.TreeRing
|
||||
import app.pachli.di.InitializerEntryPoint
|
||||
import javax.inject.Inject
|
||||
import timber.log.Timber
|
||||
|
||||
/** Initialise [Timber]. */
|
||||
class TimberInitializer : Initializer<Unit> {
|
||||
@Inject
|
||||
lateinit var logEntryTree: LogEntryTree
|
||||
|
||||
override fun create(context: Context) {
|
||||
InitializerEntryPoint.resolve(context).inject(this)
|
||||
|
||||
when {
|
||||
BuildConfig.DEBUG -> Timber.plant(Timber.DebugTree())
|
||||
BuildConfig.FLAVOR_color == "orange" -> Timber.plant(TreeRing)
|
||||
}
|
||||
Timber.plant(logEntryTree)
|
||||
}
|
||||
|
||||
override fun dependencies(): List<Class<out Initializer<*>>> {
|
||||
return listOf(DependencyGraphInitializer::class.java)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2024 Pachli Association
|
||||
*
|
||||
* This file is a part of Pachli.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||
* see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
package app.pachli.initializer
|
||||
|
||||
import android.content.Context
|
||||
import androidx.hilt.work.HiltWorkerFactory
|
||||
import androidx.startup.Initializer
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.WorkManager
|
||||
import app.pachli.di.InitializerEntryPoint
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Initialise [WorkManager] with a [HiltWorkerFactory]. */
|
||||
class WorkManagerInitializer : Initializer<WorkManager>, Configuration.Provider {
|
||||
@Inject
|
||||
lateinit var workerFactory: HiltWorkerFactory
|
||||
|
||||
override val workManagerConfiguration: Configuration
|
||||
get() = Configuration.Builder().setWorkerFactory(workerFactory).build()
|
||||
|
||||
override fun create(context: Context): WorkManager {
|
||||
InitializerEntryPoint.resolve(context).inject(this)
|
||||
|
||||
WorkManager.initialize(context, workManagerConfiguration)
|
||||
return WorkManager.getInstance(context)
|
||||
}
|
||||
|
||||
override fun dependencies(): List<Class<out Initializer<*>>> {
|
||||
return listOf(
|
||||
DependencyGraphInitializer::class.java,
|
||||
TimberInitializer::class.java,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ androidx-preference = "1.2.1"
|
|||
androidx-recyclerview = "1.3.2"
|
||||
androidx-sharetarget = "1.2.0"
|
||||
androidx-splashscreen = "1.0.1"
|
||||
androidx-startup = "1.1.1"
|
||||
androidx-swiperefresh-layout = "1.1.0"
|
||||
androidx-testing = "2.2.0"
|
||||
androidx-test-core-ktx = "1.5.0"
|
||||
|
@ -143,6 +144,7 @@ androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx
|
|||
androidx-room-testing = { module = "androidx.room:room-testing", version.ref = "androidx-room" }
|
||||
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerview" }
|
||||
androidx-sharetarget = { module = "androidx.sharetarget:sharetarget", version.ref = "androidx-sharetarget" }
|
||||
androidx-startup = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startup" }
|
||||
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefresh-layout" }
|
||||
androidx-test-core-ktx = { module = "androidx.test:core-ktx", version.ref = "androidx-test-core-ktx" }
|
||||
androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" }
|
||||
|
@ -235,8 +237,7 @@ androidx = ["androidx-core-ktx", "androidx-appcompat", "androidx-fragment-ktx",
|
|||
"androidx-constraintlayout", "androidx-paging-runtime-ktx", "androidx-viewpager2", "androidx-work-runtime-ktx",
|
||||
"androidx-core-splashscreen", "androidx-activity", "androidx-media3-exoplayer", "androidx-media3-exoplayer-dash",
|
||||
"androidx-media3-exoplayer-hls", "androidx-media3-exoplayer-rtsp", "androidx-media3-datasource-okhttp", "androidx-media3-ui",
|
||||
"androidx-transition",
|
||||
"android-material"]
|
||||
"androidx-transition", "android-material", "androidx-startup"]
|
||||
filemojicompat = ["filemojicompat-core", "filemojicompat-ui", "filemojicompat-defaults"]
|
||||
glide = ["glide-core", "glide-okhttp3-integration", "glide-animation-plugin"]
|
||||
lint-api = ["kotlin-stdlib", "lint-api", "lint-checks"]
|
||||
|
|
Loading…
Reference in New Issue