From c0128b88de718e10c20dcb9df930e4c90197074d Mon Sep 17 00:00:00 2001 From: fanchao Date: Mon, 27 May 2024 10:29:53 +1000 Subject: [PATCH] OOM feedback --- .../securesms/database/ThreadDatabase.java | 2 +- .../securesms/home/HomeAdapter.kt | 14 ++-- .../securesms/home/HomeDiffUtil.kt | 9 ++- .../securesms/home/HomeViewModel.kt | 68 +++++++++---------- .../securesms/util/ContentResolverUtils.kt | 2 +- 5 files changed, 46 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index 8f93d823c2..f5c6da5fb9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -881,7 +881,7 @@ public class ThreadDatabase extends Database { this.cursor = cursor; } - public int getLength() { + public int getCount() { return cursor == null ? 0 : cursor.getCount(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt index 071e421bf8..63e0fed5b6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeAdapter.kt @@ -25,14 +25,16 @@ class HomeAdapter( var header: View? = null - var data: HomeViewModel.HomeData = HomeViewModel.HomeData(emptyList(), emptySet()) + var data: HomeViewModel.Data = HomeViewModel.Data(emptyList(), emptySet()) set(newData) { - if (field !== newData) { - val diff = HomeDiffUtil(field, newData, context, configFactory) - val diffResult = DiffUtil.calculateDiff(diff) - field = newData - diffResult.dispatchUpdatesTo(this as ListUpdateCallback) + if (field === newData) { + return } + + val diff = HomeDiffUtil(field, newData, context, configFactory) + val diffResult = DiffUtil.calculateDiff(diff) + field = newData + diffResult.dispatchUpdatesTo(this as ListUpdateCallback) } fun hasHeaderView(): Boolean = header != null diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt index 41b7e581fb..89f02ee21a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeDiffUtil.kt @@ -2,15 +2,14 @@ package org.thoughtcrime.securesms.home import android.content.Context import androidx.recyclerview.widget.DiffUtil -import org.thoughtcrime.securesms.database.model.ThreadRecord import org.thoughtcrime.securesms.dependencies.ConfigFactory import org.thoughtcrime.securesms.util.getConversationUnread class HomeDiffUtil( - private val old: HomeViewModel.HomeData, - private val new: HomeViewModel.HomeData, - private val context: Context, - private val configFactory: ConfigFactory + private val old: HomeViewModel.Data, + private val new: HomeViewModel.Data, + private val context: Context, + private val configFactory: ConfigFactory ): DiffUtil.Callback() { override fun getOldListSize(): Int = old.threads.size diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeViewModel.kt index 0e4817994c..dccebd4156 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -30,8 +31,8 @@ import dagger.hilt.android.qualifiers.ApplicationContext as ApplicationContextQu @HiltViewModel class HomeViewModel @Inject constructor( private val threadDb: ThreadDatabase, - contentResolver: ContentResolver, - @ApplicationContextQualifier context: Context, + private val contentResolver: ContentResolver, + @ApplicationContextQualifier private val context: Context, ) : ViewModel() { // SharedFlow that emits whenever the user asks us to reload the conversation private val manualReloadTrigger = MutableSharedFlow( @@ -45,45 +46,40 @@ class HomeViewModel @Inject constructor( * This flow will emit whenever the user asks us to reload the conversation list or * whenever the conversation list changes. */ - @Suppress("OPT_IN_USAGE") - val threads: StateFlow = - combine( - // The conversation list data - merge( - manualReloadTrigger, - contentResolver.observeChanges(DatabaseContentProviders.ConversationList.CONTENT_URI)) - .debounce(CHANGE_NOTIFICATION_DEBOUNCE_MILLS) - .onStart { emit(Unit) } - .mapLatest { _ -> - withContext(Dispatchers.IO) { - threadDb.approvedConversationList.use { openCursor -> - val reader = threadDb.readerFor(openCursor) - buildList(reader.length) { - while (true) { - add(reader.next ?: break) - } - } - } - } - }, + val threads: StateFlow = combine(observeConversationList(), observeTypingStatus(), ::Data) + .stateIn(viewModelScope, SharingStarted.Eagerly, null) - // The typing status of each thread - ApplicationContext.getInstance(context).typingStatusRepository - .typingThreads - .asFlow() - .onStart { emit(emptySet()) } - .distinctUntilChanged(), + private fun observeTypingStatus(): Flow> = + ApplicationContext.getInstance(context).typingStatusRepository + .typingThreads + .asFlow() + .onStart { emit(emptySet()) } + .distinctUntilChanged() - // The final result that we emit to the UI - ::HomeData - ) - .stateIn(viewModelScope, SharingStarted.Eagerly, null) + @Suppress("OPT_IN_USAGE") + private fun observeConversationList(): Flow> = merge( + manualReloadTrigger, + contentResolver.observeChanges(DatabaseContentProviders.ConversationList.CONTENT_URI)) + .debounce(CHANGE_NOTIFICATION_DEBOUNCE_MILLS) + .onStart { emit(Unit) } + .mapLatest { _ -> + withContext(Dispatchers.IO) { + threadDb.approvedConversationList.use { openCursor -> + val reader = threadDb.readerFor(openCursor) + buildList(reader.count) { + while (true) { + add(reader.next ?: break) + } + } + } + } + } fun tryReload() = manualReloadTrigger.tryEmit(Unit) - data class HomeData( - val threads: List, - val typingThreadIDs: Set + data class Data( + val threads: List, + val typingThreadIDs: Set ) companion object { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ContentResolverUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ContentResolverUtils.kt index 0b89a3edf9..f228eb57a4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ContentResolverUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ContentResolverUtils.kt @@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow /** - * Observe changes to a content URI. This function will emit the URI whenever the content or + * Observe changes to a content Uri. This function will emit the Uri whenever the content or * its descendants change, according to the parameter [notifyForDescendants]. */ @CheckResult