Realm: avoid using monarchy thread for custom work

This commit is contained in:
ganfra 2019-07-03 14:48:45 +02:00
parent eefd09d022
commit 93ce0cc5e9
8 changed files with 75 additions and 35 deletions

View File

@ -17,7 +17,10 @@
package im.vector.matrix.android.internal.database

import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.util.createBackgroundHandler
import io.realm.OrderedCollectionChangeSet
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.RealmObject
import io.realm.RealmResults
import java.util.concurrent.atomic.AtomicBoolean
@ -29,17 +32,24 @@ internal interface LiveEntityObserver {
fun isStarted(): Boolean
}

internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val monarchy: Monarchy)
internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val realmConfiguration: RealmConfiguration)
: LiveEntityObserver {

private companion object {
val BACKGROUND_HANDLER = createBackgroundHandler("LIVE_ENTITY_BACKGROUND")
}

protected abstract val query: Monarchy.Query<T>
private val isStarted = AtomicBoolean(false)
private val backgroundRealm = AtomicReference<Realm>()
private lateinit var results: AtomicReference<RealmResults<T>>

override fun start() {
if (isStarted.compareAndSet(false, true)) {
monarchy.postToMonarchyThread {
val queryResults = query.createQuery(it).findAll()
BACKGROUND_HANDLER.post {
val realm = Realm.getInstance(realmConfiguration)
backgroundRealm.set(realm)
val queryResults = query.createQuery(realm).findAll()
queryResults.addChangeListener { t, changeSet ->
onChanged(t, changeSet)
}
@ -50,8 +60,11 @@ internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val m

override fun dispose() {
if (isStarted.compareAndSet(true, false)) {
monarchy.postToMonarchyThread {
BACKGROUND_HANDLER.post {
results.getAndSet(null).removeAllChangeListeners()
backgroundRealm.getAndSet(null).also {
it.close()
}
}
}
}

View File

@ -50,7 +50,6 @@ import javax.inject.Inject
internal class DefaultSession @Inject constructor(override val sessionParams: SessionParams,
private val context: Context,
private val liveEntityObservers: Set<@JvmSuppressWildcards LiveEntityObserver>,
private val monarchy: Monarchy,
private val sessionListeners: SessionListeners,
private val roomService: RoomService,
private val roomDirectoryService: RoomDirectoryService,
@ -66,16 +65,16 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
private val contentUrlResolver: ContentUrlResolver,
private val contentUploadProgressTracker: ContentUploadStateTracker)
: Session,
RoomService by roomService,
RoomDirectoryService by roomDirectoryService,
GroupService by groupService,
UserService by userService,
CryptoService by cryptoService,
CacheService by cacheService,
SignOutService by signOutService,
FilterService by filterService,
PushRuleService by pushRuleService,
PushersService by pushersService {
RoomService by roomService,
RoomDirectoryService by roomDirectoryService,
GroupService by groupService,
UserService by userService,
CryptoService by cryptoService,
CacheService by cacheService,
SignOutService by signOutService,
FilterService by filterService,
PushRuleService by pushRuleService,
PushersService by pushersService {

private var isOpen = false

@ -85,9 +84,6 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
assertMainThread()
assert(!isOpen)
isOpen = true
if (!monarchy.isMonarchyThreadOpen) {
monarchy.openManually()
}
liveEntityObservers.forEach { it.start() }
}

@ -123,9 +119,6 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
stopSync()
liveEntityObservers.forEach { it.dispose() }
cryptoService.close()
if (monarchy.isMonarchyThreadOpen) {
monarchy.closeManually()
}
isOpen = false
}


View File

@ -27,14 +27,16 @@ import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
import im.vector.matrix.android.internal.database.model.GroupEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import io.realm.RealmConfiguration
import javax.inject.Inject

private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"

internal class GroupSummaryUpdater @Inject constructor(private val context: Context,
private val credentials: Credentials,
monarchy: Monarchy) : RealmLiveEntityObserver<GroupEntity>(monarchy) {
@SessionDatabase realmConfiguration: RealmConfiguration) : RealmLiveEntityObserver<GroupEntity>(realmConfiguration) {

override val query = Monarchy.Query<GroupEntity> { GroupEntity.where(it) }


View File

@ -22,8 +22,10 @@ import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.query.types
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import io.realm.RealmConfiguration
import timber.log.Timber
import javax.inject.Inject

@ -33,11 +35,11 @@ import javax.inject.Inject
* The summaries can then be extracted and added (as a decoration) to a TimelineEvent for final display.
*/

internal class EventRelationsAggregationUpdater @Inject constructor(monarchy: Monarchy,
internal class EventRelationsAggregationUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
private val credentials: Credentials,
private val task: EventRelationsAggregationTask,
private val taskExecutor: TaskExecutor) :
RealmLiveEntityObserver<EventEntity>(monarchy) {
RealmLiveEntityObserver<EventEntity>(realmConfiguration) {

override val query = Monarchy.Query<EventEntity> {
EventEntity.types(it, listOf(

View File

@ -23,9 +23,11 @@ import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import io.realm.RealmConfiguration
import timber.log.Timber
import javax.inject.Inject

@ -33,11 +35,11 @@ import javax.inject.Inject
* Listens to the database for the insertion of any redaction event.
* As it will actually delete the content, it should be called last in the list of listener.
*/
internal class EventsPruner @Inject constructor(monarchy: Monarchy,
internal class EventsPruner @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
private val credentials: Credentials,
private val pruneEventTask: PruneEventTask,
private val taskExecutor: TaskExecutor) :
RealmLiveEntityObserver<EventEntity>(monarchy) {
RealmLiveEntityObserver<EventEntity>(realmConfiguration) {

override val query = Monarchy.Query<EventEntity> { EventEntity.where(it, type = EventType.REDACTION) }


View File

@ -16,9 +16,6 @@

package im.vector.matrix.android.internal.session.room.timeline

import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.events.model.EventType
@ -43,6 +40,8 @@ import im.vector.matrix.android.internal.database.query.whereInRoom
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.Debouncer
import im.vector.matrix.android.internal.util.createBackgroundHandler
import im.vector.matrix.android.internal.util.createUIHandler
import io.realm.OrderedCollectionChangeSet
import io.realm.OrderedRealmCollectionChangeListener
import io.realm.Realm
@ -75,9 +74,7 @@ internal class DefaultTimeline(
) : Timeline {

private companion object {
val BACKGROUND_HANDLER = Handler(
HandlerThread("TIMELINE_DB_THREAD").apply { start() }.looper
)
val BACKGROUND_HANDLER = createBackgroundHandler("TIMELINE_DB_THREAD")
}

override var listener: Timeline.Listener? = null
@ -90,7 +87,7 @@ internal class DefaultTimeline(

private val isStarted = AtomicBoolean(false)
private val isReady = AtomicBoolean(false)
private val mainHandler = Handler(Looper.getMainLooper())
private val mainHandler = createUIHandler()
private val backgroundRealm = AtomicReference<Realm>()
private val cancelableBag = CancelableBag()
private val debouncer = Debouncer(mainHandler)

View File

@ -22,17 +22,19 @@ import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.EventEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.TaskThread
import im.vector.matrix.android.internal.task.configureWith
import io.realm.RealmConfiguration
import io.realm.Sort
import javax.inject.Inject

internal class UserEntityUpdater @Inject constructor(monarchy: Monarchy,
internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
private val updateUserTask: UpdateUserTask,
private val taskExecutor: TaskExecutor)
: RealmLiveEntityObserver<EventEntity>(monarchy) {
: RealmLiveEntityObserver<EventEntity>(realmConfiguration) {

override val query = Monarchy.Query<EventEntity> {
EventEntity

View File

@ -0,0 +1,29 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.matrix.android.internal.util

import android.os.Handler
import android.os.HandlerThread
import android.os.Looper

fun createBackgroundHandler(name: String): Handler = Handler(
HandlerThread(name).apply { start() }.looper
)

fun createUIHandler(): Handler = Handler(
Looper.getMainLooper()
)