OOM feedback

pull/1493/head
fanchao 12 months ago
parent 31f4de22cd
commit c0128b88de

@ -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();
} }

@ -25,14 +25,16 @@ 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) {
val diff = HomeDiffUtil(field, newData, context, configFactory) return
val diffResult = DiffUtil.calculateDiff(diff)
field = newData
diffResult.dispatchUpdatesTo(this as ListUpdateCallback)
} }
val diff = HomeDiffUtil(field, newData, context, configFactory)
val diffResult = DiffUtil.calculateDiff(diff)
field = newData
diffResult.dispatchUpdatesTo(this as ListUpdateCallback)
} }
fun hasHeaderView(): Boolean = header != null fun hasHeaderView(): Boolean = header != null

@ -2,15 +2,14 @@ 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() {
override fun getOldListSize(): Int = old.threads.size override fun getOldListSize(): Int = old.threads.size

@ -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,45 +46,40 @@ 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.
*/ */
@Suppress("OPT_IN_USAGE") val threads: StateFlow<Data?> = combine(observeConversationList(), observeTypingStatus(), ::Data)
val threads: StateFlow<HomeData?> = .stateIn(viewModelScope, SharingStarted.Eagerly, null)
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)
}
}
}
}
},
// The typing status of each thread private fun observeTypingStatus(): Flow<Set<Long>> =
ApplicationContext.getInstance(context).typingStatusRepository ApplicationContext.getInstance(context).typingStatusRepository
.typingThreads .typingThreads
.asFlow() .asFlow()
.onStart { emit(emptySet()) } .onStart { emit(emptySet()) }
.distinctUntilChanged(), .distinctUntilChanged()
// The final result that we emit to the UI @Suppress("OPT_IN_USAGE")
::HomeData private fun observeConversationList(): Flow<List<ThreadRecord>> = merge(
) manualReloadTrigger,
.stateIn(viewModelScope, SharingStarted.Eagerly, null) 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) 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>
) )
companion object { companion object {

@ -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

Loading…
Cancel
Save