Fetch and map the thread list items off the main thread

The thread list subscription was launched in the room coroutine scope, which runs on the main thread, so the initial sync FFI call and the mapping of all the items and diffs were done on the main thread every time a room was opened.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benoit Marty
2026-10-12 14:33:15 +02:00
parent 23a79ad987
commit 404c26c62e
3 changed files with 8 additions and 0 deletions
@@ -158,6 +158,7 @@ class JoinedRustRoom(
inner = innerRoom.threadListService(), inner = innerRoom.threadListService(),
contentMapper = TimelineEventContentMapper(), contentMapper = TimelineEventContentMapper(),
roomCoroutineScope = roomCoroutineScope, roomCoroutineScope = roomCoroutineScope,
roomDispatcher = roomDispatcher,
) )
override val syncUpdateFlow = flow { override val syncUpdateFlow = flow {
@@ -17,10 +17,12 @@ import io.element.android.libraries.matrix.api.room.threads.ThreadsListService
import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
import io.element.android.libraries.matrix.impl.timeline.item.event.map import io.element.android.libraries.matrix.impl.timeline.item.event.map
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
@@ -33,6 +35,7 @@ import org.matrix.rustcomponents.sdk.ThreadListService as InnerThreadListService
class RustThreadsListService( class RustThreadsListService(
private val inner: InnerThreadListService, private val inner: InnerThreadListService,
private val roomCoroutineScope: CoroutineScope, private val roomCoroutineScope: CoroutineScope,
private val roomDispatcher: CoroutineDispatcher,
private val contentMapper: TimelineEventContentMapper = TimelineEventContentMapper(), private val contentMapper: TimelineEventContentMapper = TimelineEventContentMapper(),
) : ThreadsListService { ) : ThreadsListService {
private var itemSubscriptionJob: Job? = null private var itemSubscriptionJob: Job? = null
@@ -63,6 +66,8 @@ class RustThreadsListService(
updated.apply(diff, contentMapper) updated.apply(diff, contentMapper)
items.value = updated items.value = updated
} }
// Fetching and mapping the items can be costly, do not do it on the main thread
.flowOn(roomDispatcher)
.launchIn(roomCoroutineScope) .launchIn(roomCoroutineScope)
} }
@@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.test.A_TIMESTAMP
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@@ -122,6 +123,7 @@ class RustThreadsListServiceTest {
) = RustThreadsListService( ) = RustThreadsListService(
inner = inner, inner = inner,
roomCoroutineScope = backgroundScope, roomCoroutineScope = backgroundScope,
roomDispatcher = StandardTestDispatcher(testScheduler),
) )
private fun aRustThreadListUpdate() = ThreadListUpdate.Append( private fun aRustThreadListUpdate() = ThreadListUpdate.Append(