Bladeren bron

More coroutine tweaks

arkon 4 jaren geleden
bovenliggende
commit
c9cf9cfff0

+ 0 - 3
app/src/main/java/eu/kanade/tachiyomi/App.kt

@@ -20,9 +20,7 @@ import org.acra.sender.HttpSender
 import org.conscrypt.Conscrypt
 import timber.log.Timber
 import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.InjektScope
 import uy.kohesive.injekt.injectLazy
-import uy.kohesive.injekt.registry.default.DefaultRegistrar
 import java.security.Security
 
 @AcraCore(
@@ -53,7 +51,6 @@ open class App : Application(), LifecycleObserver {
             Security.insertProviderAt(Conscrypt.newProvider(), 1)
         }
 
-        Injekt = InjektScope(DefaultRegistrar())
         Injekt.importModule(AppModule(this))
 
         setupAcra()

+ 8 - 8
app/src/main/java/eu/kanade/tachiyomi/AppModule.kt

@@ -1,6 +1,7 @@
 package eu.kanade.tachiyomi
 
 import android.app.Application
+import android.os.Handler
 import com.google.gson.Gson
 import eu.kanade.tachiyomi.data.cache.ChapterCache
 import eu.kanade.tachiyomi.data.cache.CoverCache
@@ -11,8 +12,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
 import eu.kanade.tachiyomi.extension.ExtensionManager
 import eu.kanade.tachiyomi.network.NetworkHelper
 import eu.kanade.tachiyomi.source.SourceManager
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
 import kotlinx.serialization.json.Json
 import uy.kohesive.injekt.api.InjektModule
 import uy.kohesive.injekt.api.InjektRegistrar
@@ -48,15 +47,16 @@ class AppModule(val app: Application) : InjektModule {
         addSingletonFactory { Json { ignoreUnknownKeys = true } }
 
         // Asynchronously init expensive components for a faster cold start
+        Handler().post {
+            get<PreferencesHelper>()
 
-        GlobalScope.launch { get<PreferencesHelper>() }
+            get<NetworkHelper>()
 
-        GlobalScope.launch { get<NetworkHelper>() }
+            get<SourceManager>()
 
-        GlobalScope.launch { get<SourceManager>() }
+            get<DatabaseHelper>()
 
-        GlobalScope.launch { get<DatabaseHelper>() }
-
-        GlobalScope.launch { get<DownloadManager>() }
+            get<DownloadManager>()
+        }
     }
 }

+ 1 - 2
app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt

@@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.data.database.models.Track
 import eu.kanade.tachiyomi.data.track.TrackManager
 import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.util.chapter.NoChaptersException
-import eu.kanade.tachiyomi.util.lang.await
 import kotlinx.coroutines.Job
 import uy.kohesive.injekt.injectLazy
 import java.io.File
@@ -91,7 +90,7 @@ abstract class AbstractBackupRestore<T : AbstractBackupManager>(protected val co
             if (service != null && service.isLogged) {
                 try {
                     val updatedTrack = service.refresh(track)
-                    db.insertTrack(updatedTrack).await()
+                    db.insertTrack(updatedTrack).executeAsBlocking()
                 } catch (e: Exception) {
                     errors.add(Date() to "${manga.title} - ${e.message}")
                 }

+ 1 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchPresenter.kt

@@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.source.model.SManga
 import eu.kanade.tachiyomi.source.model.toSManga
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
-import eu.kanade.tachiyomi.util.lang.await
 import eu.kanade.tachiyomi.util.lang.runAsObservable
 import rx.Observable
 import rx.Subscription
@@ -255,7 +254,7 @@ open class GlobalSearchPresenter(
         val networkManga = source.getMangaDetails(manga.toMangaInfo())
         manga.copyFrom(networkManga.toSManga())
         manga.initialized = true
-        db.insertManga(manga).await()
+        db.insertManga(manga).executeAsBlocking()
         return manga
     }
 

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt

@@ -199,7 +199,7 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
             return
         }
 
-        launchIO {
+        lifecycleScope.launchIO {
             try {
                 val pendingUpdates = ExtensionGithubApi().checkForUpdates(this@MainActivity)
                 preferences.extensionUpdatesCount().set(pendingUpdates.size)

+ 4 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt

@@ -24,7 +24,6 @@ import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
 import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
 import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
 import eu.kanade.tachiyomi.util.isLocal
-import eu.kanade.tachiyomi.util.lang.await
 import eu.kanade.tachiyomi.util.lang.launchIO
 import eu.kanade.tachiyomi.util.lang.withUIContext
 import eu.kanade.tachiyomi.util.prepUpdateCover
@@ -168,7 +167,7 @@ class MangaPresenter(
                 manga.prepUpdateCover(coverCache, sManga, manualFetch)
                 manga.copyFrom(sManga)
                 manga.initialized = true
-                db.insertManga(manga).await()
+                db.insertManga(manga).executeAsBlocking()
 
                 withUIContext { view?.onFetchMangaInfoDone() }
             } catch (e: Throwable) {
@@ -350,7 +349,7 @@ class MangaPresenter(
         hasRequested = true
 
         if (fetchChaptersJob?.isActive == true) return
-        fetchChaptersJob = launchIO {
+        fetchChaptersJob = presenterScope.launchIO {
             try {
                 val chapters = source.getChapterList(manga.toMangaInfo())
                     .map { it.toSChapter() }
@@ -464,7 +463,7 @@ class MangaPresenter(
         }
 
         launchIO {
-            db.updateChaptersProgress(chapters).await()
+            db.updateChaptersProgress(chapters).executeAsBlocking()
 
             if (preferences.removeAfterMarkedAsRead()) {
                 deleteChapters(chapters)
@@ -489,7 +488,7 @@ class MangaPresenter(
             selectedChapters
                 .forEach {
                     it.bookmark = bookmarked
-                    db.updateChapterProgress(it).await()
+                    db.updateChapterProgress(it).executeAsBlocking()
                 }
         }
     }

+ 3 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt

@@ -8,7 +8,6 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.data.track.TrackManager
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
-import eu.kanade.tachiyomi.util.lang.await
 import eu.kanade.tachiyomi.util.lang.launchIO
 import eu.kanade.tachiyomi.util.lang.withUIContext
 import eu.kanade.tachiyomi.util.system.toast
@@ -67,7 +66,7 @@ class TrackPresenter(
                         .map {
                             async {
                                 val track = it.service.refresh(it.track!!)
-                                db.insertTrack(track).await()
+                                db.insertTrack(track).executeAsBlocking()
                             }
                         }
                         .awaitAll()
@@ -98,7 +97,7 @@ class TrackPresenter(
             launchIO {
                 try {
                     service.bind(item)
-                    db.insertTrack(item).await()
+                    db.insertTrack(item).executeAsBlocking()
                 } catch (e: Throwable) {
                     withUIContext { context.toast(e.message) }
                 }
@@ -116,7 +115,7 @@ class TrackPresenter(
         launchIO {
             try {
                 service.update(track)
-                db.insertTrack(track).await()
+                db.insertTrack(track).executeAsBlocking()
                 withUIContext { view?.onRefreshDone() }
             } catch (e: Throwable) {
                 withUIContext { view?.onRefreshError(e) }

+ 4 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt

@@ -21,7 +21,6 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
 import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
 import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
 import eu.kanade.tachiyomi.util.isLocal
-import eu.kanade.tachiyomi.util.lang.await
 import eu.kanade.tachiyomi.util.lang.byteSize
 import eu.kanade.tachiyomi.util.lang.launchIO
 import eu.kanade.tachiyomi.util.lang.takeBytes
@@ -664,7 +663,7 @@ class ReaderPresenter(
         val trackManager = Injekt.get<TrackManager>()
 
         launchIO {
-            db.getTracks(manga).await()
+            db.getTracks(manga).executeAsBlocking()
                 .mapNotNull { track ->
                     val service = trackManager.getService(track.sync_id)
                     if (service != null && service.isLogged && chapterRead > track.last_chapter_read) {
@@ -675,7 +674,7 @@ class ReaderPresenter(
                         async {
                             runCatching {
                                 service.update(track)
-                                db.insertTrack(track).await()
+                                db.insertTrack(track).executeAsBlocking()
                             }
                         }
                     } else {
@@ -683,8 +682,8 @@ class ReaderPresenter(
                     }
                 }
                 .awaitAll()
-                .filter { it.isFailure }
-                .forEach { it.exceptionOrNull()?.let { e -> Timber.w(e) } }
+                .mapNotNull { it.exceptionOrNull() }
+                .forEach { Timber.w(it) }
         }
     }
 

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt

@@ -1,6 +1,7 @@
 package eu.kanade.tachiyomi.ui.setting.track
 
 import android.net.Uri
+import androidx.lifecycle.lifecycleScope
 import eu.kanade.tachiyomi.util.lang.launchIO
 
 class AnilistLoginActivity : BaseOAuthLoginActivity() {
@@ -9,7 +10,7 @@ class AnilistLoginActivity : BaseOAuthLoginActivity() {
         val regex = "(?:access_token=)(.*?)(?:&)".toRegex()
         val matchResult = regex.find(data?.fragment.toString())
         if (matchResult?.groups?.get(1) != null) {
-            launchIO {
+            lifecycleScope.launchIO {
                 trackManager.aniList.login(matchResult.groups[1]!!.value)
                 returnToSettings()
             }

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt

@@ -1,6 +1,7 @@
 package eu.kanade.tachiyomi.ui.setting.track
 
 import android.net.Uri
+import androidx.lifecycle.lifecycleScope
 import eu.kanade.tachiyomi.util.lang.launchIO
 
 class BangumiLoginActivity : BaseOAuthLoginActivity() {
@@ -8,7 +9,7 @@ class BangumiLoginActivity : BaseOAuthLoginActivity() {
     override fun handleResult(data: Uri?) {
         val code = data?.getQueryParameter("code")
         if (code != null) {
-            launchIO {
+            lifecycleScope.launchIO {
                 trackManager.bangumi.login(code)
                 returnToSettings()
             }

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/MyAnimeListLoginActivity.kt

@@ -1,6 +1,7 @@
 package eu.kanade.tachiyomi.ui.setting.track
 
 import android.net.Uri
+import androidx.lifecycle.lifecycleScope
 import eu.kanade.tachiyomi.util.lang.launchIO
 
 class MyAnimeListLoginActivity : BaseOAuthLoginActivity() {
@@ -8,7 +9,7 @@ class MyAnimeListLoginActivity : BaseOAuthLoginActivity() {
     override fun handleResult(data: Uri?) {
         val code = data?.getQueryParameter("code")
         if (code != null) {
-            launchIO {
+            lifecycleScope.launchIO {
                 trackManager.myAnimeList.login(code)
                 returnToSettings()
             }

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt

@@ -1,6 +1,7 @@
 package eu.kanade.tachiyomi.ui.setting.track
 
 import android.net.Uri
+import androidx.lifecycle.lifecycleScope
 import eu.kanade.tachiyomi.util.lang.launchIO
 
 class ShikimoriLoginActivity : BaseOAuthLoginActivity() {
@@ -8,7 +9,7 @@ class ShikimoriLoginActivity : BaseOAuthLoginActivity() {
     override fun handleResult(data: Uri?) {
         val code = data?.getQueryParameter("code")
         if (code != null) {
-            launchIO {
+            lifecycleScope.launchIO {
                 trackManager.shikimori.login(code)
                 returnToSettings()
             }

+ 83 - 91
app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt

@@ -1,7 +1,5 @@
 package eu.kanade.tachiyomi.util.lang
 
-import com.pushtorefresh.storio.operations.PreparedOperation
-import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject
 import kotlinx.coroutines.CancellableContinuation
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.CoroutineStart
@@ -10,11 +8,8 @@ import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.suspendCancellableCoroutine
-import rx.Completable
-import rx.CompletableSubscriber
 import rx.Emitter
 import rx.Observable
 import rx.Observer
@@ -53,49 +48,46 @@ suspend fun <T> Single<T>.await(subscribeOn: Scheduler? = null): T {
     }
 }
 
-suspend fun <T> PreparedOperation<T>.await(): T = asRxSingle().await()
-suspend fun <T> PreparedGetObject<T>.await(): T? = asRxSingle().await()
-
-suspend fun Completable.awaitSuspending(subscribeOn: Scheduler? = null) {
-    return suspendCancellableCoroutine { continuation ->
-        val self = if (subscribeOn != null) subscribeOn(subscribeOn) else this
-        lateinit var sub: Subscription
-        sub = self.subscribe(
-            {
-                continuation.resume(Unit) {
-                    sub.unsubscribe()
-                }
-            },
-            {
-                if (!continuation.isCancelled) {
-                    continuation.resumeWithException(it)
-                }
-            }
-        )
-
-        continuation.invokeOnCancellation {
-            sub.unsubscribe()
-        }
-    }
-}
-
-suspend fun Completable.awaitCompleted(): Unit = suspendCancellableCoroutine { cont ->
-    subscribe(
-        object : CompletableSubscriber {
-            override fun onSubscribe(s: Subscription) {
-                cont.unsubscribeOnCancellation(s)
-            }
-
-            override fun onCompleted() {
-                cont.resume(Unit)
-            }
-
-            override fun onError(e: Throwable) {
-                cont.resumeWithException(e)
-            }
-        }
-    )
-}
+// suspend fun Completable.awaitSuspending(subscribeOn: Scheduler? = null) {
+//     return suspendCancellableCoroutine { continuation ->
+//         val self = if (subscribeOn != null) subscribeOn(subscribeOn) else this
+//         lateinit var sub: Subscription
+//         sub = self.subscribe(
+//             {
+//                 continuation.resume(Unit) {
+//                     sub.unsubscribe()
+//                 }
+//             },
+//             {
+//                 if (!continuation.isCancelled) {
+//                     continuation.resumeWithException(it)
+//                 }
+//             }
+//         )
+//
+//         continuation.invokeOnCancellation {
+//             sub.unsubscribe()
+//         }
+//     }
+// }
+//
+// suspend fun Completable.awaitCompleted(): Unit = suspendCancellableCoroutine { cont ->
+//     subscribe(
+//         object : CompletableSubscriber {
+//             override fun onSubscribe(s: Subscription) {
+//                 cont.unsubscribeOnCancellation(s)
+//             }
+//
+//             override fun onCompleted() {
+//                 cont.resume(Unit)
+//             }
+//
+//             override fun onError(e: Throwable) {
+//                 cont.resumeWithException(e)
+//             }
+//         }
+//     )
+// }
 
 suspend fun <T> Single<T>.await(): T = suspendCancellableCoroutine { cont ->
     cont.unsubscribeOnCancellation(
@@ -113,27 +105,27 @@ suspend fun <T> Single<T>.await(): T = suspendCancellableCoroutine { cont ->
     )
 }
 
-suspend fun <T> Observable<T>.awaitFirst(): T = first().awaitOne()
-
-suspend fun <T> Observable<T>.awaitFirstOrDefault(default: T): T =
-    firstOrDefault(default).awaitOne()
-
-suspend fun <T> Observable<T>.awaitFirstOrNull(): T? = firstOrDefault(null).awaitOne()
-
-suspend fun <T> Observable<T>.awaitFirstOrElse(defaultValue: () -> T): T = switchIfEmpty(
-    Observable.fromCallable(
-        defaultValue
-    )
-).first().awaitOne()
-
-suspend fun <T> Observable<T>.awaitLast(): T = last().awaitOne()
+// suspend fun <T> Observable<T>.awaitFirst(): T = first().awaitOne()
+//
+// suspend fun <T> Observable<T>.awaitFirstOrDefault(default: T): T =
+//     firstOrDefault(default).awaitOne()
+//
+// suspend fun <T> Observable<T>.awaitFirstOrNull(): T? = firstOrDefault(null).awaitOne()
+//
+// suspend fun <T> Observable<T>.awaitFirstOrElse(defaultValue: () -> T): T = switchIfEmpty(
+//     Observable.fromCallable(
+//         defaultValue
+//     )
+// ).first().awaitOne()
+//
+// suspend fun <T> Observable<T>.awaitLast(): T = last().awaitOne()
 
 suspend fun <T> Observable<T>.awaitSingle(): T = single().awaitOne()
 
-suspend fun <T> Observable<T>.awaitSingleOrDefault(default: T): T =
-    singleOrDefault(default).awaitOne()
-
-suspend fun <T> Observable<T>.awaitSingleOrNull(): T? = singleOrDefault(null).awaitOne()
+// suspend fun <T> Observable<T>.awaitSingleOrDefault(default: T): T =
+//     singleOrDefault(default).awaitOne()
+//
+// suspend fun <T> Observable<T>.awaitSingleOrNull(): T? = singleOrDefault(null).awaitOne()
 
 private suspend fun <T> Observable<T>.awaitOne(): T = suspendCancellableCoroutine { cont ->
     cont.unsubscribeOnCancellation(
@@ -192,31 +184,31 @@ fun <T : Any> Observable<T>.asFlow(): Flow<T> = callbackFlow {
     awaitClose { subscription.unsubscribe() }
 }
 
-fun <T : Any> Flow<T>.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable<T> {
-    return Observable.create(
-        { emitter ->
-            /*
-             * ATOMIC is used here to provide stable behaviour of subscribe+dispose pair even if
-             * asObservable is already invoked from unconfined
-             */
-            val job = GlobalScope.launch(Dispatchers.Unconfined, start = CoroutineStart.ATOMIC) {
-                try {
-                    collect { emitter.onNext(it) }
-                    emitter.onCompleted()
-                } catch (e: Throwable) {
-                    // Ignore `CancellationException` as error, since it indicates "normal cancellation"
-                    if (e !is CancellationException) {
-                        emitter.onError(e)
-                    } else {
-                        emitter.onCompleted()
-                    }
-                }
-            }
-            emitter.setCancellation { job.cancel() }
-        },
-        backpressureMode
-    )
-}
+// fun <T : Any> Flow<T>.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable<T> {
+//     return Observable.create(
+//         { emitter ->
+//             /*
+//              * ATOMIC is used here to provide stable behaviour of subscribe+dispose pair even if
+//              * asObservable is already invoked from unconfined
+//              */
+//             val job = GlobalScope.launch(Dispatchers.Unconfined, start = CoroutineStart.ATOMIC) {
+//                 try {
+//                     collect { emitter.onNext(it) }
+//                     emitter.onCompleted()
+//                 } catch (e: Throwable) {
+//                     // Ignore `CancellationException` as error, since it indicates "normal cancellation"
+//                     if (e !is CancellationException) {
+//                         emitter.onError(e)
+//                     } else {
+//                         emitter.onCompleted()
+//                     }
+//                 }
+//             }
+//             emitter.setCancellation { job.cancel() }
+//         },
+//         backpressureMode
+//     )
+// }
 
 fun <T> runAsObservable(
     block: suspend () -> T,