mirror of
https://github.com/immich-app/immich
synced 2025-10-17 18:19:27 +00:00
fix: ensure background worker is scheduled when the app is dismissed (#22032)
* fix: ensure background worker is scheduled when the app is dismissed * remove logs * fix: use native locks (#22081) * fix: native locks * use atomicints * change count check --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> --------- Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
2e945281fc
commit
b2ca208dbb
5 changed files with 45 additions and 2 deletions
|
|
@ -3,6 +3,7 @@ package app.alextran.immich
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.work.Configuration
|
import androidx.work.Configuration
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
|
import app.alextran.immich.background.BackgroundWorkerApiImpl
|
||||||
|
|
||||||
class ImmichApp : Application() {
|
class ImmichApp : Application() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
|
@ -14,6 +15,8 @@ class ImmichApp : Application() {
|
||||||
// Thus, the BackupWorker is not started. If the system kills the process after each initialization
|
// Thus, the BackupWorker is not started. If the system kills the process after each initialization
|
||||||
// (because of low memory etc.), the backup is never performed.
|
// (because of low memory etc.), the backup is never performed.
|
||||||
// As a workaround, we also run a backup check when initializing the application
|
// As a workaround, we also run a backup check when initializing the application
|
||||||
|
|
||||||
ContentObserverWorker.startBackupWorker(context = this, delayMilliseconds = 0)
|
ContentObserverWorker.startBackupWorker(context = this, delayMilliseconds = 0)
|
||||||
|
BackgroundWorkerApiImpl.enqueueBackgroundWorker(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package app.alextran.immich
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.ext.SdkExtensions
|
import android.os.ext.SdkExtensions
|
||||||
|
import app.alextran.immich.background.BackgroundEngineLock
|
||||||
import app.alextran.immich.background.BackgroundWorkerApiImpl
|
import app.alextran.immich.background.BackgroundWorkerApiImpl
|
||||||
import app.alextran.immich.background.BackgroundWorkerFgHostApi
|
import app.alextran.immich.background.BackgroundWorkerFgHostApi
|
||||||
import app.alextran.immich.connectivity.ConnectivityApi
|
import app.alextran.immich.connectivity.ConnectivityApi
|
||||||
|
|
@ -25,6 +26,7 @@ class MainActivity : FlutterFragmentActivity() {
|
||||||
fun registerPlugins(ctx: Context, flutterEngine: FlutterEngine) {
|
fun registerPlugins(ctx: Context, flutterEngine: FlutterEngine) {
|
||||||
flutterEngine.plugins.add(BackgroundServicePlugin())
|
flutterEngine.plugins.add(BackgroundServicePlugin())
|
||||||
flutterEngine.plugins.add(HttpSSLOptionsPlugin())
|
flutterEngine.plugins.add(HttpSSLOptionsPlugin())
|
||||||
|
flutterEngine.plugins.add(BackgroundEngineLock())
|
||||||
|
|
||||||
val messenger = flutterEngine.dartExecutor.binaryMessenger
|
val messenger = flutterEngine.dartExecutor.binaryMessenger
|
||||||
val nativeSyncApiImpl =
|
val nativeSyncApiImpl =
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package app.alextran.immich.background
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import io.flutter.embedding.engine.FlutterEngineCache
|
||||||
|
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
|
private const val TAG = "BackgroundEngineLock"
|
||||||
|
|
||||||
|
class BackgroundEngineLock : FlutterPlugin {
|
||||||
|
companion object {
|
||||||
|
const val ENGINE_CACHE_KEY = "immich::background_worker::engine"
|
||||||
|
var engineCount = AtomicInteger(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
|
// work manager task is running while the main app is opened, cancel the worker
|
||||||
|
if (engineCount.incrementAndGet() > 1 && FlutterEngineCache.getInstance()
|
||||||
|
.get(ENGINE_CACHE_KEY) != null
|
||||||
|
) {
|
||||||
|
WorkManager.getInstance(binding.applicationContext)
|
||||||
|
.cancelUniqueWork(BackgroundWorkerApiImpl.BACKGROUND_WORKER_NAME)
|
||||||
|
FlutterEngineCache.getInstance().remove(ENGINE_CACHE_KEY)
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Flutter engine attached. Attached Engines count: $engineCount")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
|
engineCount.decrementAndGet()
|
||||||
|
Log.i(TAG, "Flutter engine detached. Attached Engines count: $engineCount")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import io.flutter.FlutterInjector
|
import io.flutter.FlutterInjector
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.embedding.engine.FlutterEngineCache
|
||||||
import io.flutter.embedding.engine.dart.DartExecutor
|
import io.flutter.embedding.engine.dart.DartExecutor
|
||||||
import io.flutter.embedding.engine.loader.FlutterLoader
|
import io.flutter.embedding.engine.loader.FlutterLoader
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
@ -75,6 +76,9 @@ class BackgroundWorker(context: Context, params: WorkerParameters) :
|
||||||
|
|
||||||
loader.ensureInitializationCompleteAsync(ctx, null, Handler(Looper.getMainLooper())) {
|
loader.ensureInitializationCompleteAsync(ctx, null, Handler(Looper.getMainLooper())) {
|
||||||
engine = FlutterEngine(ctx)
|
engine = FlutterEngine(ctx)
|
||||||
|
FlutterEngineCache.getInstance().remove(BackgroundEngineLock.ENGINE_CACHE_KEY);
|
||||||
|
FlutterEngineCache.getInstance()
|
||||||
|
.put(BackgroundEngineLock.ENGINE_CACHE_KEY, engine!!)
|
||||||
|
|
||||||
// Register custom plugins
|
// Register custom plugins
|
||||||
MainActivity.registerPlugins(ctx, engine!!)
|
MainActivity.registerPlugins(ctx, engine!!)
|
||||||
|
|
@ -188,6 +192,7 @@ class BackgroundWorker(context: Context, params: WorkerParameters) :
|
||||||
isComplete = true
|
isComplete = true
|
||||||
engine?.destroy()
|
engine?.destroy()
|
||||||
engine = null
|
engine = null
|
||||||
|
FlutterEngineCache.getInstance().remove(BackgroundEngineLock.ENGINE_CACHE_KEY);
|
||||||
flutterApi = null
|
flutterApi = null
|
||||||
notificationManager.cancel(NOTIFICATION_ID)
|
notificationManager.cancel(NOTIFICATION_ID)
|
||||||
waitForForegroundPromotion()
|
waitForForegroundPromotion()
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val BACKGROUND_WORKER_NAME = "immich/BackgroundWorkerV1"
|
const val BACKGROUND_WORKER_NAME = "immich/BackgroundWorkerV1"
|
||||||
private const val OBSERVER_WORKER_NAME = "immich/MediaObserverV1"
|
private const val OBSERVER_WORKER_NAME = "immich/MediaObserverV1"
|
||||||
|
|
||||||
fun enqueueMediaObserver(ctx: Context) {
|
fun enqueueMediaObserver(ctx: Context) {
|
||||||
|
|
@ -56,7 +56,7 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
|
||||||
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
|
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
|
||||||
.build()
|
.build()
|
||||||
WorkManager.getInstance(ctx)
|
WorkManager.getInstance(ctx)
|
||||||
.enqueueUniqueWork(BACKGROUND_WORKER_NAME, ExistingWorkPolicy.REPLACE, work)
|
.enqueueUniqueWork(BACKGROUND_WORKER_NAME, ExistingWorkPolicy.KEEP, work)
|
||||||
|
|
||||||
Log.i(TAG, "Enqueued background worker with name: $BACKGROUND_WORKER_NAME")
|
Log.i(TAG, "Enqueued background worker with name: $BACKGROUND_WORKER_NAME")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue