【问题标题】:Calling an RxJava Single In Kotlin Lambda在 Kotlin Lambda 中调用 RxJava Single
【发布时间】:2017-11-12 15:20:05
【问题描述】:

我正在尝试修改新的 Room 库以将其与 RxJava 配对。

我找到了一种使用Single 在后台线程上插入项目的方法,就像这样,在活动内部:

Single.fromCallable { AppDatabase.getInMemoryDatabase(this).taskDao().insertAll(task) }
                    .subscribeOn(Schedulers.newThread())
                    .subscribe()

现在,我有一个包含任务的 RecyclerView,其中包含一个复选框,您可以使用该复选框将项目标记为完成与否。我想要做的是每次选中/取消选中时更新项目。我将粘贴整个 ViewHolder 以完成,但请特别注意 bindTask() 中的 lambda:

inner class TaskViewHolder(view: View?) : RecyclerView.ViewHolder(view) {
        val descriptionTextView = view?.findViewById(R.id.task_description) as? TextView
        val completedCheckBox = view?.findViewById(R.id.task_completed) as? CheckBox

        fun bindTask(task: Task) {
            descriptionTextView?.text = task.description
            completedCheckBox?.isChecked = task.completed

            completedCheckBox?.setOnCheckedChangeListener { _, isChecked ->
                tasks[adapterPosition].completed = isChecked

                Single.fromCallable { itemView.context.taskDao().update(tasks[adapterPosition]) }
                        .subscribeOn(Schedulers.newThread())
                        .subscribe()
            }
        }
    }

这适用于我检查的第一项,但之后我无法单击任何其他复选框。我认为Single 会自我毁灭,但也许我不能在 lambda 中做到这一点?我需要以某种方式将 Single 拉到外面吗?

【问题讨论】:

  • 请不要使用inner class TaskViewHolder,只使用class TaskViewHolderprevent memory leaks。也许你需要一个WeakReference 来访问外部类
  • 感谢您的建议。我已经解决了。
  • 我将使用 Observable.create(ObservableOnSubscribe{ e->emitter = e}).yourRxLogic 和 setOnCheckedChangeListener 创建成员变量发射器,我将使用发射器.onNext(someValue) 将其传递给 rx流。

标签: android rx-java kotlin rx-java2


【解决方案1】:

我将使用 Observable.create 创建 Observable,使用 lambda 保存该发射器,然后使用 setOnCheckedChangeListener 传递下一个项目 emitter.onNext()

class TaskViewHolder(view: View) : RecyclerView.ViewHolder(view)
{
    private lateinit var emitter: ObservableEmitter<Task>
    private val disposable: Disposable = Observable.create(ObservableOnSubscribe<Task> { e -> emitter = e })
            .subscribeOn(Schedulers.newThread())
            .observeOn(Schedulers.newThread())
            .subscribe({ itemView.context.taskDao().update(it) })
    val descriptionTextView = view?.findViewById(R.id.task_description) as? TextView
    val completedCheckBox = view?.findViewById(R.id.task_completed) as? CheckBox

    fun bindTask(task: Task) {
        descriptionTextView?.text = task.description
        completedCheckBox?.isChecked = task.completed

        completedCheckBox?.setOnCheckedChangeListener { _, isChecked ->
            tasks[adapterPosition].completed = isChecked
            emitter.onNext(tasks[adapterPosition])
        }
    }
}

【讨论】:

  • 你能举例说明如何为更新代码添加 Rx 逻辑吗?我尝试将.subscribeOn(Schedulers.newThread()).subscribe({ itemView.context.taskDao().update(it) }) 放在一次性用品上,但我继续收到“无法访问主线程上的数据库”错误。
  • 好吧,你的订阅很好,尝试使用.observeOn(Schedulers.newThread())而不是subscribeOn,你实际上是在主UI线程上订阅。
  • 这对我有用!我将用我的确切代码更新答案,以帮助任何未来的读者。谢谢! :)
【解决方案2】:

我还没有测试过,但这应该可以工作

class TaskViewHolder(view: View?) : RecyclerView.ViewHolder(view) {

    val descriptionTextView: TextView? = null
    val completedCheckBox: CheckBox? = null

    fun bindTask(task: Task) {
        descriptionTextView?.text = task.description
        completedCheckBox?.isChecked = task.completed

        completedCheckBox?.setOnCheckedChangeListener { _, isChecked ->
            tasks[adapterPosition].completed = isChecked

            itemView.context.taskDao().update(tasks[adapterPosition])
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ changeCount -> Timber.i("%,d item(s) updated", changeCount) },
                           { error -> Timber.e(error, "update failed") })
        }
    }
}

interface TaskDao {
    fun update(task: Task): Flowable<Int>
}

我没有创建新的Single,而是使用RxJava functionality or Room

【讨论】:

  • Hmm Room 告诉我更新方法必须返回 void 或 int。有没有可能Flowable只能用于查询?
  • 我玩过 Room 和 RxJava,但没有组合使用 :-( 你有没有将 android.arch.persistence.room:rxjava2 添加到你的 build.gradle 中
  • 是的,我有。我认为它仅用于查询。对于插入、更新和删除,我必须创建 Flowables/Singles/WhateverRxComponent 才能在新线程上执行此操作。我以为这就是我在这里所做的,但幕后正在发生一些我不完全理解的事情
  • 我想我可以在活动中调用onPause() 时访问该列表,并让它循环并更新整个列表?解决这个问题会很好,但我认为这就是我将同时尝试的。
猜你喜欢
  • 2017-08-04
  • 1970-01-01
  • 2019-02-10
  • 1970-01-01
  • 1970-01-01
  • 2023-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多