【问题标题】:What's the best way to use Rxjava to get Dialog's input values?使用 Rxjava 获取 Dialog 的输入值的最佳方法是什么?
【发布时间】:2019-12-09 13:16:52
【问题描述】:

我在 Activity 中有一个按钮。当我按下这个按钮时,我想在从另一个 Dialog 接收到输入值后,用输入值执行一些功能。

我在以下配置中实现了这个请求。

视图模型

package k.test.mvvmmock

import androidx.databinding.BaseObservable
import io.reactivex.Single

class MainViewModel(val contract: Contract) : BaseObservable() {

interface Contract {
    fun showDialog(): Single<String>
}


fun clickButton(){
    contract.showDialog()
        .subscribe({
            //Something Action
            println("Input : $it")
        },{

        })
}
}

活动

package k.test.mvvmmock

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import io.reactivex.Single
import android.content.DialogInterface
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.databinding.DataBindingUtil
import io.reactivex.subjects.SingleSubject
import k.test.mvvmmock.databinding.ActivityMainBinding
import java.lang.Exception


class MainActivity : AppCompatActivity(), MainViewModel.Contract {
val viewModel = MainViewModel(this)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        .vm = viewModel
}

override fun showDialog(): Single<String> {
    val txt = EditText(this)
    val subject = SingleSubject.create<String>()
    val dialog = AlertDialog.Builder(this)
        .setTitle("Input")
        .setView(txt)
        .setPositiveButton("OK") { _, _ ->
            subject.onSuccess(txt.text.toString())
        }
        .setNegativeButton("Cancel") { _, _ ->
            subject.onError(Exception("Canceled!"))
        }
        .create()

    return subject.doOnSubscribe {
        dialog.show()
    }
        .doFinally {
            if(dialog.isShowing)
                dialog.dismiss()
        }
}
}

布局

<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
    <variable name="vm" type="k.test.mvvmmock.MainViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            android:onClick="@{(v)->vm.clickButton()}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

一般贴出的代码,当需要在ViewModel中弹出对话框时,一般会使用Activity通过Subject订阅ViewModel的方式,但是从Dialog接收任意值返回给ViewModel的流程是不一致。

以上代码还需要将接收Activity输入值的接口一一传递给ViewModel。

我想改进这段代码,但我真的没有一个好主意。

【问题讨论】:

    标签: android mvvm dialog rx-java viewmodel


    【解决方案1】:

    如果应用将 View 引用传递给 ViewModel,则该应用未遵循 MVVM 模式。如果一个应用遵循 MVVM,它的 ViewModel 层不需要知道任何关于它的 View 层的信息。

    当前MainViewModel 的问题在于它“告诉”视图显示对话框,并将对话框数据“获取”回自身。流程应该是相反的。 MainActivity 应该是“观察”事件并将数据“提供”给MainViewModel

    例子:

    MainViewModel

    class MainViewModel : BaseObservable() { // No Contract!
    
        val showDialogEvent = PublishSubject.create<Any>();
    
        fun clickButton() {
            showDialogEvent.onNext(Any())
        }
    
        fun doThingsWith(dialogInput: String) {
            // do something here
            println("Input : $it")
        }
    
        fun handleError(e: Throwable) {
            // do something here
        }
    

    MainActivity

    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            ...
    
            val disposable = viewModel.showDialogEvent
                .subscribe {
                    val txt = EditText(this)
                    val subject = SingleSubject.create<String>()
                    val dialog = AlertDialog.Builder(this)
                        .setTitle("Input")
                        .setView(txt)
                        .setPositiveButton("OK") { _, _ ->
                            viewModel.doThingsWith(txt.text.toString())
                        }
                        .setNegativeButton("Cancel") { _, _ ->
                            viewModel.handleError(Exception("Canceled!"))
                        }
                        .create()
    
                    dialog.show()
                }
        }
    

    此外,如果ViewModel 不需要知道点击,您可以通过直接从MainActivity 为按钮设置点击侦听器来进一步简化流程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 1970-01-01
      • 2019-07-26
      • 2020-04-10
      • 2010-10-07
      相关资源
      最近更新 更多