Fix some crashes

- Delay the initial emission of updates/sources/extensions lists instead of using a state flow. This hopefully avoids rapid initial recompositions that cause the LazyColumn key duplication crashes. (Closes #8371)
- Fix a NPE in BrowseSourcePresenter
This commit is contained in:
arkon 2022-10-30 18:43:16 -04:00
parent cac80daa71
commit 5d1f79012e
4 changed files with 11 additions and 7 deletions

View File

@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
@ -22,7 +23,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -116,7 +117,7 @@ class ExtensionsPresenter(
items items
} }
.stateIn(presenterScope) .onStart { delay(500) } // Defer to avoid crashing on initial render
.collectLatest { .collectLatest {
state.isLoading = false state.isLoading = false
state.items = it state.items = it

View File

@ -14,10 +14,11 @@ import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import logcat.LogPriority import logcat.LogPriority
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -43,7 +44,7 @@ class SourcesPresenter(
logcat(LogPriority.ERROR, exception) logcat(LogPriority.ERROR, exception)
_events.send(Event.FailedFetchingSources) _events.send(Event.FailedFetchingSources)
} }
.stateIn(presenterScope) .onStart { delay(500) } // Defer to avoid crashing on initial render
.collectLatest(::collectLatestSources) .collectLatest(::collectLatestSources)
} }
} }

View File

@ -154,7 +154,8 @@ open class BrowseSourcePresenter(
} }
fun reset() { fun reset() {
state.filters = source!!.getFilterList() val source = source ?: return
state.filters = source.getFilterList()
if (currentFilter !is Filter.UserInput) return if (currentFilter !is Filter.UserInput) return
state.currentFilter = (currentFilter as Filter.UserInput).copy(filters = state.filters) state.currentFilter = (currentFilter as Filter.UserInput).copy(filters = state.filters)
} }

View File

@ -29,13 +29,14 @@ import eu.kanade.tachiyomi.util.lang.launchNonCancellable
import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.lang.withUIContext
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import logcat.LogPriority import logcat.LogPriority
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -87,11 +88,11 @@ class UpdatesPresenter(
getUpdates.subscribe(calendar).distinctUntilChanged(), getUpdates.subscribe(calendar).distinctUntilChanged(),
downloadCache.changes, downloadCache.changes,
) { updates, _ -> updates } ) { updates, _ -> updates }
.onStart { delay(500) } // Defer to avoid crashing on initial render
.catch { .catch {
logcat(LogPriority.ERROR, it) logcat(LogPriority.ERROR, it)
_events.send(Event.InternalError) _events.send(Event.InternalError)
} }
.stateIn(presenterScope)
.collectLatest { updates -> .collectLatest { updates ->
state.items = updates.toUpdateItems() state.items = updates.toUpdateItems()
state.isLoading = false state.isLoading = false