当 Observable.create() 发出侦听器对象时避免内存泄漏

Avoid memory leak when Observable.create() to emit listener objects

我正在围绕 FirebaseFirestore 快照侦听器编写一个包装器,它使用 RxKotlin Observable 发出更改。

我编写了以下 class,它使用 create() 方法创建可观察对象并在新数据快照可用时异步发出更改。

问题是每次我创建此 class 的实例并停止使用它时都会泄漏内存。在不泄漏内存的情况下重写此 class 的最佳方法是什么?

关于如何创建可以从侦听器发出对象的 Observable 的任何资源都非常有用!

class DocumentRepository<T : ModelWithMetadata>(
        path: List<String>,
        private val model: Class<T>) {

    private var documentReference: DocumentReference

    val observable: Observable<T>

    private var emitter: ObservableEmitter<T>? = null
    private lateinit var item: T


    init {
        documentReference = FirebaseFirestore.getInstance().collection(path[0]).document(path[1])
        for (i in 2..path.lastIndex step 2)
            documentReference = documentReference.collection(path[i]).document(path[i + 1])

        observable = Observable.create(this::listenChanges)
    }

    private fun listenChanges(emitter: ObservableEmitter<T>) {
        this.emitter = emitter
        documentReference.addSnapshotListener { documentSnapshot, _ ->
            item = documentSnapshot.toObject(this.model)
            this.emitter?.onNext(item)
        }
    }

    fun get() {
        emitter?.onNext(item)
    }

    fun put(item: T) {
        item.updatedAt = TimeExtension.now()
        documentReference.set(item)
    }

    fun delete(item: T) {
        documentReference.delete()
    }
}

documentReference.addSnapshotListener returns 一个 ListenerRegistration which allows you to call ListenerRegistration#remove 删除侦听器。

并且,Emitter#setCancellable 允许您清理资源,在这种情况下,当 Observable 取消订阅时分离侦听器。

所以你的 listenChanges 看起来像这样:

private fun listenChanges(emitter: ObservableEmitter<T>) {
  this.emitter = emitter
  val registration = documentReference.addSnapshotListener { documentSnapshot, _ ->
    item = documentSnapshot.toObject(this.model)
    this.emitter?.onNext(item)
  }
  emitter.setCancellable { registration.remove() }
}