From 6fb7a85e8a77aa379a8138e1f2fe1b5f65b45ed7 Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 7 Jan 2021 18:15:57 -0500 Subject: [PATCH] Address more coroutine scope leaks --- app/build.gradle.kts | 2 +- .../data/download/DownloadProvider.kt | 6 ++-- .../ui/base/presenter/BasePresenter.kt | 11 +++++++ .../details/ExtensionDetailsHeaderAdapter.kt | 6 +--- .../ui/browse/source/SourcePresenter.kt | 7 +---- .../ui/browse/source/filter/TextItem.kt | 6 ++-- .../ui/library/LibraryCategoryView.kt | 6 ++-- .../chapter/MangaChaptersHeaderAdapter.kt | 6 +--- .../ui/manga/info/MangaInfoHeaderAdapter.kt | 30 ++++++++----------- .../ui/reader/viewer/ViewerConfig.kt | 6 +--- .../ui/reader/viewer/pager/PagerConfig.kt | 8 +++-- .../ui/reader/viewer/pager/PagerViewer.kt | 11 ++++++- .../ui/reader/viewer/webtoon/WebtoonConfig.kt | 6 +++- .../ui/reader/viewer/webtoon/WebtoonViewer.kt | 7 ++++- .../ui/setting/SettingsBackupController.kt | 8 ++--- .../ui/setting/SettingsBrowseController.kt | 2 +- .../ui/setting/SettingsController.kt | 6 ++-- .../ui/setting/SettingsDownloadController.kt | 6 ++-- .../ui/setting/SettingsGeneralController.kt | 4 +-- .../ui/setting/SettingsLibraryController.kt | 6 ++-- .../ui/setting/SettingsReaderController.kt | 10 +++---- .../ui/setting/SettingsSecurityController.kt | 2 +- .../widget/DialogCustomDownloadView.kt | 6 ++-- 23 files changed, 85 insertions(+), 83 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 16f1c2e21b..680da6a41a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -272,7 +272,7 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion") // For detecting memory leaks; see https://square.github.io/leakcanary/ -// debugImplementation("com.squareup.leakcanary:leakcanary-android:2.4") + // debugImplementation("com.squareup.leakcanary:leakcanary-android:2.6") } tasks { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt index 87f982b2b2..418332683d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt @@ -9,9 +9,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.util.storage.DiskUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import timber.log.Timber @@ -27,7 +25,7 @@ class DownloadProvider(private val context: Context) { private val preferences: PreferencesHelper by injectLazy() - private val scope = CoroutineScope(Job() + Dispatchers.Main) + private val scope = MainScope() /** * The root directory for downloads. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt index c8eb46e5b2..185b01d73e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt @@ -1,21 +1,32 @@ package eu.kanade.tachiyomi.ui.base.presenter import android.os.Bundle +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel import nucleus.presenter.RxPresenter import nucleus.presenter.delivery.Delivery import rx.Observable open class BasePresenter : RxPresenter() { + lateinit var presenterScope: CoroutineScope + override fun onCreate(savedState: Bundle?) { try { super.onCreate(savedState) + presenterScope = MainScope() } catch (e: NullPointerException) { // Swallow this error. This should be fixed in the library but since it's not critical // (only used by restartables) it should be enough. It saves me a fork. } } + override fun onDestroy() { + super.onDestroy() + presenterScope.cancel() + } + /** * Subscribes an observable with [deliverFirst] and adds it to the presenter's lifecycle * subscription list. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsHeaderAdapter.kt index 6a98fdf37b..93099bbbd0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsHeaderAdapter.kt @@ -9,9 +9,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.databinding.ExtensionDetailHeaderBinding import eu.kanade.tachiyomi.ui.browse.extension.getApplicationIcon import eu.kanade.tachiyomi.util.system.LocaleHelper -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.view.clicks @@ -19,7 +16,6 @@ import reactivecircus.flowbinding.android.view.clicks class ExtensionDetailsHeaderAdapter(private val presenter: ExtensionDetailsPresenter) : RecyclerView.Adapter() { - private val scope = CoroutineScope(Job() + Dispatchers.Main) private lateinit var binding: ExtensionDetailHeaderBinding override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder { @@ -47,7 +43,7 @@ class ExtensionDetailsHeaderAdapter(private val presenter: ExtensionDetailsPrese binding.extensionUninstallButton.clicks() .onEach { presenter.uninstallExtension() } - .launchIn(scope) + .launchIn(presenter.presenterScope) if (extension.isObsolete) { binding.extensionWarningBanner.isVisible = true diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt index a51deafb5d..dd465efe1a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt @@ -6,9 +6,6 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop @@ -33,8 +30,6 @@ class SourcePresenter( private val preferences: PreferencesHelper = Injekt.get() ) : BasePresenter() { - private val scope = CoroutineScope(Job() + Dispatchers.Main) - var sources = getEnabledSources() /** @@ -98,7 +93,7 @@ class SourcePresenter( .onStart { delay(500) } .distinctUntilChanged() .onEach { updateLastUsedSource(it) } - .launchIn(scope) + .launchIn(presenterScope) } private fun updateLastUsedSource(sourceId: Long) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/TextItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/TextItem.kt index d3d4eb3f7f..149114c1dd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/TextItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/TextItem.kt @@ -10,16 +10,14 @@ import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.viewholders.FlexibleViewHolder import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.model.Filter -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.widget.textChanges open class TextItem(val filter: Filter.Text) : AbstractFlexibleItem() { - private val scope = CoroutineScope(Job() + Dispatchers.Main) + private val scope = MainScope() override fun getLayoutRes(): Int { return R.layout.navigation_view_text diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt index 2ed7373209..e33db2c15a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt @@ -19,9 +19,7 @@ import eu.kanade.tachiyomi.util.lang.plusAssign import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.inflate import eu.kanade.tachiyomi.widget.AutofitRecyclerView -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.recyclerview.scrollStateChanges @@ -37,7 +35,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemLongClickListener { - private val scope = CoroutineScope(Job() + Dispatchers.Main) + private val scope = MainScope() private val preferences: PreferencesHelper by injectLazy() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt index ff2039b6f1..6485c37ffb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt @@ -9,9 +9,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.databinding.MangaChaptersHeaderBinding import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.util.system.getResourceColor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach @@ -25,7 +22,6 @@ class MangaChaptersHeaderAdapter( private var numChapters: Int? = null private var hasActiveFilters: Boolean = false - private val scope = CoroutineScope(Job() + Dispatchers.Main) private lateinit var binding: MangaChaptersHeaderBinding override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder { @@ -68,7 +64,7 @@ class MangaChaptersHeaderAdapter( merge(view.clicks(), binding.btnChaptersFilter.clicks()) .onEach { controller.showSettingsSheet() } - .launchIn(scope) + .launchIn(controller.viewScope) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt index 77c3f4df09..ee3e6ddb32 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt @@ -23,9 +23,6 @@ import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.util.system.copyToClipboard import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.view.setChips -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach @@ -47,7 +44,6 @@ class MangaInfoHeaderAdapter( private var source: Source = controller.presenter.source private var trackCount: Int = 0 - private val scope = CoroutineScope(Job() + Dispatchers.Main) private lateinit var binding: MangaInfoHeaderBinding private var initialLoad: Boolean = true @@ -90,12 +86,12 @@ class MangaInfoHeaderAdapter( binding.btnFavorite.clicks() .onEach { controller.onFavoriteClick() } - .launchIn(scope) + .launchIn(controller.viewScope) if (controller.presenter.manga.favorite && controller.presenter.getCategories().isNotEmpty()) { binding.btnFavorite.longClicks() .onEach { controller.onCategoriesClick() } - .launchIn(scope) + .launchIn(controller.viewScope) } with(binding.btnTracking) { @@ -118,7 +114,7 @@ class MangaInfoHeaderAdapter( clicks() .onEach { controller.onTrackingClick() } - .launchIn(scope) + .launchIn(controller.viewScope) } else { isVisible = false } @@ -128,7 +124,7 @@ class MangaInfoHeaderAdapter( binding.btnWebview.isVisible = true binding.btnWebview.clicks() .onEach { controller.openMangaInWebView() } - .launchIn(scope) + .launchIn(controller.viewScope) } binding.mangaFullTitle.longClicks() @@ -138,13 +134,13 @@ class MangaInfoHeaderAdapter( binding.mangaFullTitle.text.toString() ) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaFullTitle.clicks() .onEach { controller.performGlobalSearch(binding.mangaFullTitle.text.toString()) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaAuthor.longClicks() .onEach { @@ -153,13 +149,13 @@ class MangaInfoHeaderAdapter( binding.mangaAuthor.text.toString() ) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaAuthor.clicks() .onEach { controller.performGlobalSearch(binding.mangaAuthor.text.toString()) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaArtist.longClicks() .onEach { @@ -168,13 +164,13 @@ class MangaInfoHeaderAdapter( binding.mangaArtist.text.toString() ) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaArtist.clicks() .onEach { controller.performGlobalSearch(binding.mangaArtist.text.toString()) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaSummaryText.longClicks() .onEach { @@ -183,7 +179,7 @@ class MangaInfoHeaderAdapter( binding.mangaSummaryText.text.toString() ) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaCover.longClicks() .onEach { @@ -192,7 +188,7 @@ class MangaInfoHeaderAdapter( controller.presenter.manga.title ) } - .launchIn(scope) + .launchIn(controller.viewScope) setMangaInfo(manga, source) } @@ -300,7 +296,7 @@ class MangaInfoHeaderAdapter( binding.mangaInfoToggleLess.clicks() ) .onEach { toggleMangaInfo() } - .launchIn(scope) + .launchIn(controller.viewScope) // Expand manga info if navigated from source listing if (initialLoad && fromSource) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt index 35354a9dc7..5f33726688 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt @@ -4,8 +4,6 @@ import com.tfcporciuncula.flow.Preference import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode import eu.kanade.tachiyomi.data.preference.PreferencesHelper import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -13,9 +11,7 @@ import kotlinx.coroutines.flow.onEach /** * Common configuration for all viewers. */ -abstract class ViewerConfig(preferences: PreferencesHelper) { - - private val scope = CoroutineScope(Job() + Dispatchers.Main) +abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: CoroutineScope) { var imagePropertyChangedListener: (() -> Unit)? = null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt index c2e5f1470d..3243c2ec49 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt @@ -6,14 +6,18 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.EdgeNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.KindlishNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation +import kotlinx.coroutines.CoroutineScope import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get /** * Configuration used by pager viewers. */ -class PagerConfig(private val viewer: PagerViewer, preferences: PreferencesHelper = Injekt.get()) : - ViewerConfig(preferences) { +class PagerConfig( + private val viewer: PagerViewer, + scope: CoroutineScope, + preferences: PreferencesHelper = Injekt.get() +) : ViewerConfig(preferences, scope) { var imageScaleType = 1 private set diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt index 3607e4fa6d..d6499a350d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt @@ -16,6 +16,8 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel import timber.log.Timber import kotlin.math.min @@ -25,6 +27,8 @@ import kotlin.math.min @Suppress("LeakingThis") abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { + private val scope = MainScope() + /** * View pager used by this viewer. It's abstract to implement L2R, R2L and vertical pagers on * top of this class. @@ -34,7 +38,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { /** * Configuration used by the pager, like allow taps, scale mode on images, page transitions... */ - val config = PagerConfig(this) + val config = PagerConfig(this, scope) /** * Adapter of the pager. @@ -114,6 +118,11 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { } } + override fun destroy() { + super.destroy() + scope.cancel() + } + /** * Creates a new ViewPager. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt index 1a37b56685..255fad0ae5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt @@ -6,13 +6,17 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.EdgeNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.KindlishNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation +import kotlinx.coroutines.CoroutineScope import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get /** * Configuration used by webtoon viewers. */ -class WebtoonConfig(preferences: PreferencesHelper = Injekt.get()) : ViewerConfig(preferences) { +class WebtoonConfig( + scope: CoroutineScope, + preferences: PreferencesHelper = Injekt.get() +) : ViewerConfig(preferences, scope) { var imageCropBorders = false private set diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index a78ef9db92..30c47e2f4d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -16,6 +16,8 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel import rx.subscriptions.CompositeSubscription import timber.log.Timber import kotlin.math.max @@ -26,6 +28,8 @@ import kotlin.math.min */ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true) : BaseViewer { + private val scope = MainScope() + /** * Recycler view used by this viewer. */ @@ -59,7 +63,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr /** * Configuration used by this viewer, like allow taps, or crop image borders. */ - val config = WebtoonConfig() + val config = WebtoonConfig(scope) /** * Subscriptions to keep while this viewer is used. @@ -168,6 +172,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr */ override fun destroy() { super.destroy() + scope.cancel() subscriptions.unsubscribe() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt index ed7936ec85..68ac22e632 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt @@ -133,14 +133,14 @@ class SettingsBackupController : SettingsController() { } preferences.backupInterval().asImmediateFlow { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) preferences.backupsDirectory().asFlow() .onEach { path -> val dir = UniFile.fromUri(context, path.toUri()) summary = dir.filePath + "/automatic" } - .launchIn(scope) + .launchIn(viewScope) } intListPreference { key = Keys.numberOfBackups @@ -151,7 +151,7 @@ class SettingsBackupController : SettingsController() { summary = "%s" preferences.backupInterval().asImmediateFlow { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { key = Keys.createLegacyBackup @@ -159,7 +159,7 @@ class SettingsBackupController : SettingsController() { defaultValue = true preferences.backupInterval().asImmediateFlow { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt index 35ab62c3b6..4156b9c21a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt @@ -64,7 +64,7 @@ class SettingsBrowseController : SettingsController() { titleRes = R.string.pref_label_nsfw_extension defaultValue = true - preferences.showNsfwExtension().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.showNsfwExtension().asImmediateFlow { isVisible = it }.launchIn(viewScope) } infoPreference(R.string.parental_controls_info) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt index f1f2ecda3e..2d0287451b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt @@ -22,9 +22,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.base.controller.RootController import eu.kanade.tachiyomi.util.system.getResourceColor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import rx.Observable import rx.Subscription import rx.subscriptions.CompositeSubscription @@ -35,7 +33,7 @@ abstract class SettingsController : PreferenceController() { var preferenceKey: String? = null val preferences: PreferencesHelper = Injekt.get() - val scope = CoroutineScope(Job() + Dispatchers.Main) + val viewScope = MainScope() var untilDestroySubscriptions = CompositeSubscription() private set diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt index 02201b1b9c..ecb74d32ea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt @@ -57,7 +57,7 @@ class SettingsDownloadController : SettingsController() { val dir = UniFile.fromUri(context, path.toUri()) summary = dir.filePath ?: path } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { key = Keys.downloadOnlyOverWifi @@ -112,7 +112,7 @@ class SettingsDownloadController : SettingsController() { entryValues = categories.map { it.id.toString() }.toTypedArray() preferences.downloadNew().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) preferences.downloadNewCategories().asFlow() .onEach { mutableSet -> @@ -126,7 +126,7 @@ class SettingsDownloadController : SettingsController() { selectedCategories.joinToString { it.name } } } - .launchIn(scope) + .launchIn(viewScope) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt index 4eb37c7a30..f139f95de6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt @@ -116,7 +116,7 @@ class SettingsGeneralController : SettingsController() { summary = "%s" preferences.themeMode().asImmediateFlow { isVisible = it != Values.ThemeMode.dark } - .launchIn(scope) + .launchIn(viewScope) onChange { if (preferences.themeMode().get() != Values.ThemeMode.dark) { @@ -142,7 +142,7 @@ class SettingsGeneralController : SettingsController() { summary = "%s" preferences.themeMode().asImmediateFlow { isVisible = it != Values.ThemeMode.light } - .launchIn(scope) + .launchIn(viewScope) onChange { if (preferences.themeMode().get() != Values.ThemeMode.light) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt index 69f78e0c8b..e8c7df68b2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt @@ -70,7 +70,7 @@ class SettingsLibraryController : SettingsController() { summary = "${context.getString(R.string.portrait)}: $portrait, " + "${context.getString(R.string.landscape)}: $landscape" } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { key = Keys.jumpToChapters @@ -150,7 +150,7 @@ class SettingsLibraryController : SettingsController() { defaultValue = setOf("wifi") preferences.libraryUpdateInterval().asImmediateFlow { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) onChange { // Post to event looper to allow the preference to be updated. @@ -180,7 +180,7 @@ class SettingsLibraryController : SettingsController() { selectedCategories.joinToString { it.name } } } - .launchIn(scope) + .launchIn(viewScope) } intListPreference { key = Keys.libraryUpdatePrioritization diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index e49c57b516..8be74a476a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -150,7 +150,7 @@ class SettingsReaderController : SettingsController() { defaultValue = "0" summary = "%s" - preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(viewScope) } listPreference { key = Keys.pagerNavInverted @@ -170,7 +170,7 @@ class SettingsReaderController : SettingsController() { defaultValue = TappingInvertMode.NONE.name summary = "%s" - preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(viewScope) } intListPreference { key = Keys.imageScaleType @@ -223,7 +223,7 @@ class SettingsReaderController : SettingsController() { defaultValue = "0" summary = "%s" - preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(viewScope) } listPreference { key = Keys.webtoonNavInverted @@ -243,7 +243,7 @@ class SettingsReaderController : SettingsController() { defaultValue = TappingInvertMode.NONE.name summary = "%s" - preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(viewScope) } intListPreference { key = Keys.webtoonSidePadding @@ -289,7 +289,7 @@ class SettingsReaderController : SettingsController() { titleRes = R.string.pref_read_with_volume_keys_inverted defaultValue = false - preferences.readWithVolumeKeys().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithVolumeKeys().asImmediateFlow { isVisible = it }.launchIn(viewScope) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt index ba8e9a6500..87798287e4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt @@ -39,7 +39,7 @@ class SettingsSecurityController : SettingsController() { summary = "%s" preferences.useBiometricLock().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt index f0bd354c98..88cc34a64d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt @@ -7,9 +7,7 @@ import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import eu.kanade.tachiyomi.databinding.DownloadCustomAmountBinding -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.widget.textChanges @@ -37,7 +35,7 @@ class DialogCustomDownloadView @JvmOverloads constructor(context: Context, attrs */ private var max = 0 - private val scope = CoroutineScope(Job() + Dispatchers.Main) + private val scope = MainScope() private val binding: DownloadCustomAmountBinding