mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-03 16:50:40 +02:00
perf(download): reduce progress wakeups and harden retries
This commit is contained in:
@@ -374,6 +374,7 @@ class DownloadService : Service() {
|
||||
@Volatile private var nativeWorkerCancelRequested = false
|
||||
internal var nativeWorkerDownloadNetworkMode = "any"
|
||||
internal var nativeWorkerNetworkCallback: ConnectivityManager.NetworkCallback? = null
|
||||
internal var nativeWorkerNetworkFallbackJob: Job? = null
|
||||
internal val nativeWorkerWifiNetworks = mutableSetOf<Network>()
|
||||
// Bumped every time a new native queue replaces the current one. A worker
|
||||
// coroutine that observes a different generation than its own must stop
|
||||
|
||||
@@ -94,6 +94,17 @@ internal fun DownloadService.configureNativeWorkerNetworkPolicy(settingsJson: St
|
||||
"DownloadService",
|
||||
"Failed to monitor Wi-Fi for native worker: ${e.message}",
|
||||
)
|
||||
// Callback registration can fail when the process/system callback quota is
|
||||
// exhausted. Keep the Wi-Fi-only queue observable instead of leaving it
|
||||
// paused forever with no event capable of resuming it.
|
||||
nativeWorkerNetworkFallbackJob?.cancel()
|
||||
nativeWorkerNetworkFallbackJob = serviceScope.launch {
|
||||
while (NativeWorkerPolicy.requiresWifi(nativeWorkerDownloadNetworkMode)) {
|
||||
delay(5_000)
|
||||
refreshNativeWorkerNetworkPause()
|
||||
if (nativeWorkerJob?.isActive != true) break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +170,8 @@ internal fun DownloadService.refreshNativeWorkerNetworkPause() {
|
||||
}
|
||||
|
||||
internal fun DownloadService.unregisterNativeWorkerNetworkCallback() {
|
||||
nativeWorkerNetworkFallbackJob?.cancel()
|
||||
nativeWorkerNetworkFallbackJob = null
|
||||
val callback = nativeWorkerNetworkCallback
|
||||
nativeWorkerNetworkCallback = null
|
||||
synchronized(nativeWorkerWifiNetworks) {
|
||||
|
||||
@@ -329,7 +329,7 @@ internal fun DownloadService.cancelNativeWorkerProgressCoordinator() {
|
||||
private fun DownloadService.pollNativeWorkerProgress(generation: Long): Set<String> {
|
||||
val sinceSeq = synchronized(nativeWorkerProgressLock) { nativeWorkerProgressSeq }
|
||||
val raw = try {
|
||||
Gobackend.getAllDownloadProgressDelta(sinceSeq)
|
||||
Gobackend.waitForAllDownloadProgressDelta(sinceSeq, 5_000L)
|
||||
} catch (_: Exception) {
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
"com.zarz.spotiflac/download_progress_stream"
|
||||
private val LIBRARY_SCAN_PROGRESS_STREAM_CHANNEL =
|
||||
"com.zarz.spotiflac/library_scan_progress_stream"
|
||||
private val DOWNLOAD_PROGRESS_STREAM_POLLING_INTERVAL_MS = 1200L
|
||||
// A progress bar can't show sub-second granularity; 400ms halves the
|
||||
// disk-read wakeups during a scan vs the previous 200ms.
|
||||
private val LIBRARY_SCAN_PROGRESS_STREAM_POLLING_INTERVAL_MS = 400L
|
||||
@@ -482,12 +481,17 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
while (isActive && downloadProgressEventSink === sink) {
|
||||
try {
|
||||
val payload = withContext(Dispatchers.IO) {
|
||||
Gobackend.getAllDownloadProgressDelta(lastDownloadProgressSeq)
|
||||
Gobackend.waitForAllDownloadProgressDelta(
|
||||
lastDownloadProgressSeq,
|
||||
15_000L,
|
||||
)
|
||||
}
|
||||
if (!isActive || downloadProgressEventSink !== sink) break
|
||||
if (payload.isNotEmpty() && payload != lastDownloadProgressPayload) {
|
||||
updateDownloadProgressSeq(payload)
|
||||
lastDownloadProgressPayload = payload
|
||||
sink.success(parseJsonPayload(payload))
|
||||
delay(250L)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.w(
|
||||
@@ -495,7 +499,7 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
"Download progress stream poll failed: ${e.message}",
|
||||
)
|
||||
}
|
||||
delay(DOWNLOAD_PROGRESS_STREAM_POLLING_INTERVAL_MS)
|
||||
if (downloadProgressEventSink !== sink) break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -517,6 +521,7 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
val initialPayload = withContext(Dispatchers.IO) {
|
||||
readLibraryScanProgressJsonForStream()
|
||||
}
|
||||
if (!isActive || libraryScanProgressEventSink !== sink) return@launch
|
||||
lastLibraryScanProgressPayload = initialPayload
|
||||
sink.success(parseJsonPayload(initialPayload))
|
||||
} catch (e: Exception) {
|
||||
@@ -530,6 +535,7 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
val payload = withContext(Dispatchers.IO) {
|
||||
readLibraryScanProgressJsonForStream()
|
||||
}
|
||||
if (!isActive || libraryScanProgressEventSink !== sink) break
|
||||
if (payload != lastLibraryScanProgressPayload) {
|
||||
lastLibraryScanProgressPayload = payload
|
||||
sink.success(parseJsonPayload(payload))
|
||||
|
||||
Reference in New Issue
Block a user