Use generics with BaseCoroutinePresenter

Which has helped the app not run out of memory and crash 🥳 try as i might it's fairly stable now

Too anyone reading this. I'm very happy, I didn't even make these changes for memory management
This commit is contained in:
Jays2Kings 2022-04-21 23:39:19 -04:00
parent 3cabd7f6f5
commit 9f4a6698be
9 changed files with 54 additions and 44 deletions

View file

@ -5,15 +5,19 @@ import android.view.View
import androidx.viewbinding.ViewBinding
import eu.kanade.tachiyomi.ui.base.presenter.BaseCoroutinePresenter
abstract class BaseCoroutineController<VB : ViewBinding, PS : BaseCoroutinePresenter>(bundle: Bundle? = null) :
abstract class BaseCoroutineController<VB : ViewBinding, PS : BaseCoroutinePresenter<*>>(bundle: Bundle? = null) :
BaseController<VB>(bundle) {
abstract val presenter: PS
override fun onViewCreated(view: View) {
super.onViewCreated(view)
presenter.takeView(this)
presenter.onCreate()
}
@Suppress("UNCHECKED_CAST")
private fun <View> BaseCoroutinePresenter<View>.takeView(view: Any) = attachView(view as? View)
override fun onDestroyView(view: View) {
super.onDestroyView(view)
presenter.onDestroy()

View file

@ -5,8 +5,18 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
open class BaseCoroutinePresenter {
open class BaseCoroutinePresenter<T> {
lateinit var presenterScope: CoroutineScope
protected var controller: T? = null
/**
* Attaches a view to the presenter.
*
* @param view a view to attach.
*/
open fun attachView(view: T?) {
controller = view
}
open fun onCreate() {
presenterScope = CoroutineScope(Job() + Dispatchers.Default)
@ -14,5 +24,6 @@ open class BaseCoroutinePresenter {
open fun onDestroy() {
presenterScope.cancel()
controller = null
}
}

View file

@ -40,10 +40,9 @@ typealias ExtensionIntallInfo = Pair<InstallStep, PackageInstaller.SessionInfo?>
* Presenter of [ExtensionBottomSheet].
*/
class ExtensionBottomPresenter(
private val bottomSheet: ExtensionBottomSheet,
private val extensionManager: ExtensionManager = Injekt.get(),
val preferences: PreferencesHelper = Injekt.get()
) : BaseCoroutinePresenter() {
) : BaseCoroutinePresenter<ExtensionBottomSheet>() {
private var extensions = emptyList<ExtensionItem>()
@ -73,7 +72,7 @@ class ExtensionBottomPresenter(
extensionManager.availableExtensions
)
)
withContext(Dispatchers.Main) { bottomSheet.setExtensions(extensions, false) }
withContext(Dispatchers.Main) { controller?.setExtensions(extensions, false) }
}
val migrationJob = async {
val favs = db.getFavoriteMangas().executeOnIO()
@ -88,9 +87,9 @@ class ExtensionBottomPresenter(
)
withContext(Dispatchers.Main) {
if (selectedSource != null) {
bottomSheet.setMigrationManga(mangaItems[selectedSource])
controller?.setMigrationManga(mangaItems[selectedSource])
} else {
bottomSheet.setMigrationSources(sourceItems)
controller?.setMigrationSources(sourceItems)
}
}
}
@ -110,7 +109,7 @@ class ExtensionBottomPresenter(
extensionManager.availableExtensions
)
)
withUIContext { bottomSheet.setExtensions(extensions) }
withUIContext { controller?.setExtensions(extensions) }
return@collect
}
val extension = extensions.find { item ->
@ -126,7 +125,7 @@ class ExtensionBottomPresenter(
}
val item = updateInstallStep(extension.extension, it.second.first, it.second.second)
if (item != null) {
withUIContext { bottomSheet.downloadUpdate(item) }
withUIContext { controller?.downloadUpdate(item) }
}
}
}
@ -153,7 +152,7 @@ class ExtensionBottomPresenter(
extensionManager.availableExtensions
)
)
withContext(Dispatchers.Main) { bottomSheet.setExtensions(extensions, false) }
withContext(Dispatchers.Main) { controller?.setExtensions(extensions, false) }
}
}
@ -168,9 +167,9 @@ class ExtensionBottomPresenter(
)
withContext(Dispatchers.Main) {
if (selectedSource != null) {
bottomSheet.setMigrationManga(mangaItems[selectedSource])
controller?.setMigrationManga(mangaItems[selectedSource])
} else {
bottomSheet.setMigrationSources(sourceItems)
controller?.setMigrationSources(sourceItems)
}
}
}
@ -178,7 +177,7 @@ class ExtensionBottomPresenter(
@Synchronized
private fun toItems(tuple: ExtensionTuple): List<ExtensionItem> {
val context = bottomSheet.context
val context = controller?.context ?: return emptyList()
val activeLangs = preferences.enabledLanguages().get()
val showNsfwSources = preferences.showNsfwSources().get()
@ -266,7 +265,7 @@ class ExtensionBottomPresenter(
}
private fun extensionInstallDate(pkgName: String): Long {
val context = bottomSheet.context
val context = controller?.context ?: return 0
return try {
context.packageManager.getPackageInfo(pkgName, 0).firstInstallTime
} catch (e: java.lang.Exception) {
@ -275,7 +274,7 @@ class ExtensionBottomPresenter(
}
private fun extensionUpdateDate(pkgName: String): Long {
val context = bottomSheet.context
val context = controller?.context ?: return 0
return try {
context.packageManager.getPackageInfo(pkgName, 0).lastUpdateTime
} catch (e: java.lang.Exception) {
@ -331,15 +330,15 @@ class ExtensionBottomPresenter(
fun updateExtensions(extensions: List<Extension.Installed>) {
if (extensions.isEmpty()) return
val context = bottomSheet.context
val context = controller?.context ?: return
extensions.forEach {
val pkgName = it.pkgName
currentDownloads[pkgName] = InstallStep.Pending to null
val item = updateInstallStep(it, InstallStep.Pending, null) ?: return@forEach
bottomSheet.downloadUpdate(item)
controller?.downloadUpdate(item)
}
val intent = ExtensionInstallService.jobIntent(
bottomSheet.context,
context,
extensions.mapNotNull { extension ->
extensionManager.availableExtensions.find { it.pkgName == extension.pkgName }
}
@ -362,14 +361,14 @@ class ExtensionBottomPresenter(
fun setSelectedSource(source: Source) {
selectedSource = source.id
presenterScope.launch {
withContext(Dispatchers.Main) { bottomSheet.setMigrationManga(mangaItems[source.id]) }
withContext(Dispatchers.Main) { controller?.setMigrationManga(mangaItems[source.id]) }
}
}
fun deselectSource() {
selectedSource = null
presenterScope.launch {
withContext(Dispatchers.Main) { bottomSheet.setMigrationSources(sourceItems) }
withContext(Dispatchers.Main) { controller?.setMigrationSources(sourceItems) }
}
}
}

View file

@ -61,7 +61,7 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
val adapters
get() = listOf(extAdapter, migAdapter)
val presenter = ExtensionBottomPresenter(this)
val presenter = ExtensionBottomPresenter()
private var extensions: List<ExtensionItem> = emptyList()
var canExpand = false
@ -84,6 +84,7 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
fun onCreate(controller: BrowseController) {
// Initialize adapter, scroll listener and recycler views
presenter.attachView(this)
extAdapter = ExtensionAdapter(this)
extAdapter?.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY
if (migAdapter == null) {
@ -386,6 +387,13 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
presenter.uninstallExtension(pkgName)
}
/**
* Called when the view of this adapter is being destroyed.
*/
fun onDestroy() {
presenter.onDestroy()
}
private inner class TabbedSheetAdapter : RecyclerViewPagerAdapter() {
override fun getCount(): Int {
@ -451,16 +459,5 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
val index = adapters.indexOfFirst { it == view.binding?.recycler?.adapter }
return if (index == -1) POSITION_NONE else index
}
/**
* Called when the view of this adapter is being destroyed.
*/
fun onDestroy() {
/*for (view in boundViews) {
if (view is LibraryCategoryView) {
view.onDestroy()
}
}*/
}
}
}

View file

@ -176,7 +176,7 @@ class LibraryController(
private var lastItemPosition: Int? = null
private var lastItem: IFlexible<*>? = null
override var presenter = LibraryPresenter(this)
override var presenter = LibraryPresenter()
private var observeLater: Boolean = false
var searchItem = SearchGlobalItem()

View file

@ -56,14 +56,13 @@ import kotlin.random.Random
* Presenter of [LibraryController].
*/
class LibraryPresenter(
private val view: LibraryController,
val db: DatabaseHelper = Injekt.get(),
private val preferences: PreferencesHelper = Injekt.get(),
private val coverCache: CoverCache = Injekt.get(),
val sourceManager: SourceManager = Injekt.get(),
private val downloadManager: DownloadManager = Injekt.get(),
private val chapterFilter: ChapterFilter = Injekt.get()
) : BaseCoroutinePresenter() {
) : BaseCoroutinePresenter<LibraryController>() {
private val context = preferences.context
@ -133,7 +132,7 @@ class LibraryPresenter(
// Doing this instead of a job in case the app isn't used often
presenterScope.launchIO {
setSearchSuggestion(preferences, db, sourceManager)
withUIContext { view.setTitle() }
withUIContext { controller?.setTitle() }
}
}
}
@ -184,7 +183,7 @@ class LibraryPresenter(
preferences.lastUsedCategory().set(order)
val category = categories.find { it.order == order }?.id ?: return
currentCategory = category
view.onNextLibraryUpdate(
controller?.onNextLibraryUpdate(
sectionedLibraryItems[currentCategory] ?: blankItem()
)
}
@ -205,7 +204,7 @@ class LibraryPresenter(
if (!show && currentCategory == -1) currentCategory = categories.find {
it.order == preferences.lastUsedCategory().get()
}?.id ?: 0
view.onNextLibraryUpdate(
controller?.onNextLibraryUpdate(
if (!show) sectionedLibraryItems[currentCategory]
?: sectionedLibraryItems[categories.first().id] ?: blankItem()
else libraryItems,
@ -227,7 +226,7 @@ class LibraryPresenter(
it.order == preferences.lastUsedCategory().get()
}?.id ?: 0
withUIContext {
view.onNextLibraryUpdate(
controller?.onNextLibraryUpdate(
if (!showAll) sectionedLibraryItems[currentCategory]
?: sectionedLibraryItems[categories.first().id] ?: blankItem()
else libraryItems,
@ -763,7 +762,7 @@ class LibraryPresenter(
/** Create a default category with the sort set */
private fun createDefaultCategory(): Category {
val default = Category.createDefault(view.applicationContext ?: context)
val default = Category.createDefault(controller?.applicationContext ?: context)
default.order = -1
val defOrder = preferences.defaultMangaOrder().get()
if (defOrder.firstOrNull()?.isLetter() == true) default.mangaSort = defOrder.first()

View file

@ -111,7 +111,7 @@ class RecentsController(bundle: Bundle? = null) :
var displaySheet: TabbedRecentsOptionsSheet? = null
private var progressItem: ProgressItem? = null
override var presenter = RecentsPresenter(this)
override var presenter = RecentsPresenter()
private var snack: Snackbar? = null
private var lastChapterId: Long? = null
private var showingDownloads = false

View file

@ -38,12 +38,11 @@ import java.util.concurrent.TimeUnit
import kotlin.math.abs
class RecentsPresenter(
val controller: RecentsController?,
val preferences: PreferencesHelper = Injekt.get(),
val downloadManager: DownloadManager = Injekt.get(),
private val db: DatabaseHelper = Injekt.get(),
private val chapterFilter: ChapterFilter = Injekt.get()
) : BaseCoroutinePresenter(), DownloadQueue.DownloadListener, LibraryServiceListener, DownloadServiceListener {
) : BaseCoroutinePresenter<RecentsController>(), DownloadQueue.DownloadListener, LibraryServiceListener, DownloadServiceListener {
private var recentsJob: Job? = null
var recentItems = listOf<RecentMangaItem>()
@ -518,7 +517,7 @@ class RecentsPresenter(
private set
suspend fun getRecentManga(includeRead: Boolean = false): List<Pair<Manga, Long>> {
val presenter = RecentsPresenter(null)
val presenter = RecentsPresenter()
presenter.viewType = 1
SHORT_LIMIT = if (includeRead) 50 else 25
presenter.runRecents(limit = true, includeReadAnyway = includeRead)

View file

@ -419,6 +419,7 @@ class BrowseController :
override fun onDestroyView(view: View) {
adapter = null
binding.bottomSheet.root.onDestroy()
super.onDestroyView(view)
}