No crash when room is already destroyed...

This commit is contained in:
ganfra 2023-07-28 13:40:18 +02:00
parent 962596b417
commit ca4bbbc050
5 changed files with 52 additions and 28 deletions

View file

@ -16,6 +16,7 @@
package io.element.android.libraries.matrix.impl.room package io.element.android.libraries.matrix.impl.room
import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.trySendBlocking import kotlinx.coroutines.channels.trySendBlocking
@ -40,9 +41,15 @@ fun RoomList.loadingStateFlow(): Flow<RoomListLoadingState> =
trySendBlocking(state) trySendBlocking(state)
} }
} }
val result = loadingState(listener) tryOrNull {
send(result.state) val result = loadingState(listener)
result.stateStream try {
send(result.state)
} catch (exception: Exception) {
Timber.d("loadingStateFlow() initialState failed.")
}
result.stateStream
}
}.buffer(Channel.UNLIMITED) }.buffer(Channel.UNLIMITED)
fun RoomList.entriesFlow(onInitialList: suspend (List<RoomListEntry>) -> Unit): Flow<List<RoomListEntriesUpdate>> = fun RoomList.entriesFlow(onInitialList: suspend (List<RoomListEntry>) -> Unit): Flow<List<RoomListEntriesUpdate>> =
@ -52,9 +59,27 @@ fun RoomList.entriesFlow(onInitialList: suspend (List<RoomListEntry>) -> Unit):
trySendBlocking(roomEntriesUpdate) trySendBlocking(roomEntriesUpdate)
} }
} }
val result = entries(listener) tryOrNull {
onInitialList(result.entries) val result = entries(listener)
result.entriesStream try {
onInitialList(result.entries)
} catch (exception: Exception) {
Timber.d(exception, "entriesFlow() onInitialList failed.")
}
result.entriesStream
}
}.buffer(Channel.UNLIMITED)
fun RoomListService.stateFlow(): Flow<RoomListServiceState> =
mxCallbackFlow {
val listener = object : RoomListServiceStateListener {
override fun onUpdate(state: RoomListServiceState) {
trySendBlocking(state)
}
}
tryOrNull {
state(listener)
}
}.buffer(Channel.UNLIMITED) }.buffer(Channel.UNLIMITED)
fun RoomListService.roomOrNull(roomId: String): RoomListItem? { fun RoomListService.roomOrNull(roomId: String): RoomListItem? {
@ -65,13 +90,3 @@ fun RoomListService.roomOrNull(roomId: String): RoomListItem? {
return null return null
} }
} }
fun RoomListService.stateFlow(): Flow<RoomListServiceState> =
mxCallbackFlow {
val listener = object : RoomListServiceStateListener {
override fun onUpdate(state: RoomListServiceState) {
trySendBlocking(state)
}
}
state(listener)
}.buffer(Channel.UNLIMITED)

View file

@ -16,6 +16,7 @@
package io.element.android.libraries.matrix.impl.sync package io.element.android.libraries.matrix.impl.sync
import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.trySendBlocking import kotlinx.coroutines.channels.trySendBlocking
@ -32,5 +33,7 @@ fun SyncService.stateFlow(): Flow<SyncServiceState> =
trySendBlocking(state) trySendBlocking(state)
} }
} }
state(listener) tryOrNull {
state(listener)
}
}.buffer(Channel.UNLIMITED) }.buffer(Channel.UNLIMITED)

View file

@ -16,6 +16,8 @@
package io.element.android.libraries.matrix.impl.timeline package io.element.android.libraries.matrix.impl.timeline
import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
import io.element.android.libraries.matrix.impl.util.destroyAll import io.element.android.libraries.matrix.impl.util.destroyAll
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
@ -35,14 +37,14 @@ import timber.log.Timber
internal fun Room.timelineDiffFlow(onInitialList: suspend (List<TimelineItem>) -> Unit): Flow<TimelineDiff> = internal fun Room.timelineDiffFlow(onInitialList: suspend (List<TimelineItem>) -> Unit): Flow<TimelineDiff> =
callbackFlow { callbackFlow {
val roomId = id()
Timber.d("Open timelineDiffFlow for room $roomId")
val listener = object : TimelineListener { val listener = object : TimelineListener {
override fun onUpdate(diff: TimelineDiff) { override fun onUpdate(diff: TimelineDiff) {
trySendBlocking(diff) trySendBlocking(diff)
} }
} }
var result: RoomTimelineListenerResult? = null var result: RoomTimelineListenerResult? = null
val roomId = tryOrNull { id() }
Timber.d("Open timelineDiffFlow for room $roomId")
try { try {
result = addTimelineListener(listener) result = addTimelineListener(listener)
onInitialList(result.items) onInitialList(result.items)
@ -51,8 +53,7 @@ internal fun Room.timelineDiffFlow(onInitialList: suspend (List<TimelineItem>) -
} }
awaitClose { awaitClose {
Timber.d("Close timelineDiffFlow for room $roomId") Timber.d("Close timelineDiffFlow for room $roomId")
result?.itemsStream?.cancel() result?.itemsStream?.cancelAndDestroy()
result?.itemsStream?.destroy()
result?.items?.destroyAll() result?.items?.destroyAll()
} }
}.buffer(Channel.UNLIMITED) }.buffer(Channel.UNLIMITED)
@ -64,5 +65,7 @@ internal fun Room.backPaginationStatusFlow(): Flow<BackPaginationStatus> =
trySendBlocking(status) trySendBlocking(status)
} }
} }
subscribeToBackPaginationStatus(listener) tryOrNull {
subscribeToBackPaginationStatus(listener)
}
}.buffer(Channel.UNLIMITED) }.buffer(Channel.UNLIMITED)

View file

@ -21,11 +21,10 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import org.matrix.rustcomponents.sdk.TaskHandle import org.matrix.rustcomponents.sdk.TaskHandle
internal fun <T> mxCallbackFlow(block: suspend ProducerScope<T>.() -> TaskHandle) = internal fun <T> mxCallbackFlow(block: suspend ProducerScope<T>.() -> TaskHandle?) =
callbackFlow { callbackFlow {
val token: TaskHandle = block(this) val token: TaskHandle? = block(this)
awaitClose { awaitClose {
token.cancel() token?.cancelAndDestroy()
token.destroy()
} }
} }

View file

@ -28,9 +28,13 @@ class TaskHandleBag(private val tokens: MutableSet<TaskHandle> = CopyOnWriteArra
fun dispose() { fun dispose() {
tokens.forEach { tokens.forEach {
it.cancel() it.cancelAndDestroy()
it.destroy()
} }
tokens.clear() tokens.clear()
} }
} }
fun TaskHandle.cancelAndDestroy() {
cancel()
destroy()
}