OOM feedback

This commit is contained in:
fanchao 2024-05-27 10:29:53 +10:00
parent 31f4de22cd
commit c0128b88de
5 changed files with 47 additions and 50 deletions

View File

@ -881,7 +881,7 @@ public class ThreadDatabase extends Database {
this.cursor = cursor; this.cursor = cursor;
} }
public int getLength() { public int getCount() {
return cursor == null ? 0 : cursor.getCount(); return cursor == null ? 0 : cursor.getCount();
} }

View File

@ -25,15 +25,17 @@ class HomeAdapter(
var header: View? = null var header: View? = null
var data: HomeViewModel.HomeData = HomeViewModel.HomeData(emptyList(), emptySet()) var data: HomeViewModel.Data = HomeViewModel.Data(emptyList(), emptySet())
set(newData) { set(newData) {
if (field !== newData) { if (field === newData) {
return
}
val diff = HomeDiffUtil(field, newData, context, configFactory) val diff = HomeDiffUtil(field, newData, context, configFactory)
val diffResult = DiffUtil.calculateDiff(diff) val diffResult = DiffUtil.calculateDiff(diff)
field = newData field = newData
diffResult.dispatchUpdatesTo(this as ListUpdateCallback) diffResult.dispatchUpdatesTo(this as ListUpdateCallback)
} }
}
fun hasHeaderView(): Boolean = header != null fun hasHeaderView(): Boolean = header != null

View File

@ -2,13 +2,12 @@ package org.thoughtcrime.securesms.home
import android.content.Context import android.content.Context
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import org.thoughtcrime.securesms.database.model.ThreadRecord
import org.thoughtcrime.securesms.dependencies.ConfigFactory import org.thoughtcrime.securesms.dependencies.ConfigFactory
import org.thoughtcrime.securesms.util.getConversationUnread import org.thoughtcrime.securesms.util.getConversationUnread
class HomeDiffUtil( class HomeDiffUtil(
private val old: HomeViewModel.HomeData, private val old: HomeViewModel.Data,
private val new: HomeViewModel.HomeData, private val new: HomeViewModel.Data,
private val context: Context, private val context: Context,
private val configFactory: ConfigFactory private val configFactory: ConfigFactory
): DiffUtil.Callback() { ): DiffUtil.Callback() {

View File

@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -30,8 +31,8 @@ import dagger.hilt.android.qualifiers.ApplicationContext as ApplicationContextQu
@HiltViewModel @HiltViewModel
class HomeViewModel @Inject constructor( class HomeViewModel @Inject constructor(
private val threadDb: ThreadDatabase, private val threadDb: ThreadDatabase,
contentResolver: ContentResolver, private val contentResolver: ContentResolver,
@ApplicationContextQualifier context: Context, @ApplicationContextQualifier private val context: Context,
) : ViewModel() { ) : ViewModel() {
// SharedFlow that emits whenever the user asks us to reload the conversation // SharedFlow that emits whenever the user asks us to reload the conversation
private val manualReloadTrigger = MutableSharedFlow<Unit>( private val manualReloadTrigger = MutableSharedFlow<Unit>(
@ -45,11 +46,18 @@ class HomeViewModel @Inject constructor(
* This flow will emit whenever the user asks us to reload the conversation list or * This flow will emit whenever the user asks us to reload the conversation list or
* whenever the conversation list changes. * whenever the conversation list changes.
*/ */
val threads: StateFlow<Data?> = combine(observeConversationList(), observeTypingStatus(), ::Data)
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
private fun observeTypingStatus(): Flow<Set<Long>> =
ApplicationContext.getInstance(context).typingStatusRepository
.typingThreads
.asFlow()
.onStart { emit(emptySet()) }
.distinctUntilChanged()
@Suppress("OPT_IN_USAGE") @Suppress("OPT_IN_USAGE")
val threads: StateFlow<HomeData?> = private fun observeConversationList(): Flow<List<ThreadRecord>> = merge(
combine(
// The conversation list data
merge(
manualReloadTrigger, manualReloadTrigger,
contentResolver.observeChanges(DatabaseContentProviders.ConversationList.CONTENT_URI)) contentResolver.observeChanges(DatabaseContentProviders.ConversationList.CONTENT_URI))
.debounce(CHANGE_NOTIFICATION_DEBOUNCE_MILLS) .debounce(CHANGE_NOTIFICATION_DEBOUNCE_MILLS)
@ -58,30 +66,18 @@ class HomeViewModel @Inject constructor(
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
threadDb.approvedConversationList.use { openCursor -> threadDb.approvedConversationList.use { openCursor ->
val reader = threadDb.readerFor(openCursor) val reader = threadDb.readerFor(openCursor)
buildList(reader.length) { buildList(reader.count) {
while (true) { while (true) {
add(reader.next ?: break) add(reader.next ?: break)
} }
} }
} }
} }
}, }
// The typing status of each thread
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)
fun tryReload() = manualReloadTrigger.tryEmit(Unit) fun tryReload() = manualReloadTrigger.tryEmit(Unit)
data class HomeData( data class Data(
val threads: List<ThreadRecord>, val threads: List<ThreadRecord>,
val typingThreadIDs: Set<Long> val typingThreadIDs: Set<Long>
) )

View File

@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow 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]. * its descendants change, according to the parameter [notifyForDescendants].
*/ */
@CheckResult @CheckResult