Fix crashes when opening Thread (#6463)

This commit is contained in:
ganfra 2022-07-05 17:00:01 +02:00
parent d957e24747
commit 0743140973
3 changed files with 22 additions and 11 deletions

1
changelog.d/6463.bugfix Normal file
View File

@ -0,0 +1 @@
Fix crashes when opening Thread

View File

@ -20,6 +20,7 @@ import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.android.asCoroutineDispatcher import kotlinx.coroutines.android.asCoroutineDispatcher
import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.cancelChildren
@ -116,6 +117,7 @@ internal class DefaultTimeline(
) )
private var strategy: LoadTimelineStrategy = buildStrategy(LoadTimelineStrategy.Mode.Live) private var strategy: LoadTimelineStrategy = buildStrategy(LoadTimelineStrategy.Mode.Live)
private var startTimelineJob: Job? = null
override val isLive: Boolean override val isLive: Boolean
get() = !getPaginationState(Timeline.Direction.FORWARDS).hasMoreToLoad get() = !getPaginationState(Timeline.Direction.FORWARDS).hasMoreToLoad
@ -143,7 +145,7 @@ internal class DefaultTimeline(
timelineScope.launch { timelineScope.launch {
loadRoomMembersIfNeeded() loadRoomMembersIfNeeded()
} }
timelineScope.launch { startTimelineJob = timelineScope.launch {
sequencer.post { sequencer.post {
if (isStarted.compareAndSet(false, true)) { if (isStarted.compareAndSet(false, true)) {
isFromThreadTimeline = rootThreadEventId != null isFromThreadTimeline = rootThreadEventId != null
@ -174,10 +176,12 @@ internal class DefaultTimeline(
override fun restartWithEventId(eventId: String?) { override fun restartWithEventId(eventId: String?) {
timelineScope.launch { timelineScope.launch {
sequencer.post {
openAround(eventId, rootThreadEventId) openAround(eventId, rootThreadEventId)
postSnapshot() postSnapshot()
} }
} }
}
override fun hasMoreToLoad(direction: Timeline.Direction): Boolean { override fun hasMoreToLoad(direction: Timeline.Direction): Boolean {
return getPaginationState(direction).hasMoreToLoad return getPaginationState(direction).hasMoreToLoad
@ -185,6 +189,7 @@ internal class DefaultTimeline(
override fun paginate(direction: Timeline.Direction, count: Int) { override fun paginate(direction: Timeline.Direction, count: Int) {
timelineScope.launch { timelineScope.launch {
startTimelineJob?.join()
val postSnapshot = loadMore(count, direction, fetchOnServerIfNeeded = true) val postSnapshot = loadMore(count, direction, fetchOnServerIfNeeded = true)
if (postSnapshot) { if (postSnapshot) {
postSnapshot() postSnapshot()
@ -193,6 +198,7 @@ internal class DefaultTimeline(
} }
override suspend fun awaitPaginate(direction: Timeline.Direction, count: Int): List<TimelineEvent> { override suspend fun awaitPaginate(direction: Timeline.Direction, count: Int): List<TimelineEvent> {
startTimelineJob?.join()
withContext(timelineDispatcher) { withContext(timelineDispatcher) {
loadMore(count, direction, fetchOnServerIfNeeded = true) loadMore(count, direction, fetchOnServerIfNeeded = true)
} }
@ -279,6 +285,7 @@ internal class DefaultTimeline(
direction = Timeline.Direction.BACKWARDS, direction = Timeline.Direction.BACKWARDS,
fetchOnServerIfNeeded = false fetchOnServerIfNeeded = false
) )
Timber.v("$baseLogMessage finished") Timber.v("$baseLogMessage finished")
} }
@ -312,11 +319,13 @@ internal class DefaultTimeline(
private fun onLimitedTimeline() { private fun onLimitedTimeline() {
timelineScope.launch { timelineScope.launch {
sequencer.post {
initPaginationStates(null) initPaginationStates(null)
loadMore(settings.initialSize, Timeline.Direction.BACKWARDS, false) loadMore(settings.initialSize, Timeline.Direction.BACKWARDS, false)
postSnapshot() postSnapshot()
} }
} }
}
private fun onEventsDeleted() { private fun onEventsDeleted() {
// Some event have been deleted, for instance when a user has been ignored. // Some event have been deleted, for instance when a user has been ignored.

View File

@ -32,6 +32,7 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.api.settings.LightweightSettingsStorage import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
import org.matrix.android.sdk.internal.database.awaitTransaction
import org.matrix.android.sdk.internal.database.helper.addIfNecessary import org.matrix.android.sdk.internal.database.helper.addIfNecessary
import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
import org.matrix.android.sdk.internal.database.model.ChunkEntity import org.matrix.android.sdk.internal.database.model.ChunkEntity
@ -265,7 +266,7 @@ internal class LoadTimelineStrategy constructor(
} }
} }
private fun getChunkEntity(realm: Realm): RealmResults<ChunkEntity> { private suspend fun getChunkEntity(realm: Realm): RealmResults<ChunkEntity> {
return when (mode) { return when (mode) {
is Mode.Live -> { is Mode.Live -> {
ChunkEntity.where(realm, roomId) ChunkEntity.where(realm, roomId)
@ -289,8 +290,8 @@ internal class LoadTimelineStrategy constructor(
* Clear any existing thread chunk entity and create a new one, with the * Clear any existing thread chunk entity and create a new one, with the
* rootThreadEventId included. * rootThreadEventId included.
*/ */
private fun recreateThreadChunkEntity(realm: Realm, rootThreadEventId: String) { private suspend fun recreateThreadChunkEntity(realm: Realm, rootThreadEventId: String) {
realm.executeTransaction { awaitTransaction(realm.configuration) {
// Lets delete the chunk and start a new one // Lets delete the chunk and start a new one
ChunkEntity.findLastForwardChunkOfThread(it, roomId, rootThreadEventId)?.deleteAndClearThreadEvents()?.let { ChunkEntity.findLastForwardChunkOfThread(it, roomId, rootThreadEventId)?.deleteAndClearThreadEvents()?.let {
Timber.i("###THREADS LoadTimelineStrategy [onStart] thread chunk cleared..") Timber.i("###THREADS LoadTimelineStrategy [onStart] thread chunk cleared..")
@ -309,8 +310,8 @@ internal class LoadTimelineStrategy constructor(
/** /**
* Clear any existing thread chunk. * Clear any existing thread chunk.
*/ */
private fun clearThreadChunkEntity(realm: Realm, rootThreadEventId: String) { private suspend fun clearThreadChunkEntity(realm: Realm, rootThreadEventId: String) {
realm.executeTransaction { awaitTransaction(realm.configuration) {
ChunkEntity.findLastForwardChunkOfThread(it, roomId, rootThreadEventId)?.deleteAndClearThreadEvents()?.let { ChunkEntity.findLastForwardChunkOfThread(it, roomId, rootThreadEventId)?.deleteAndClearThreadEvents()?.let {
Timber.i("###THREADS LoadTimelineStrategy [onStop] thread chunk cleared..") Timber.i("###THREADS LoadTimelineStrategy [onStop] thread chunk cleared..")
} }