android - 使用 Rxjava 获取 Dialog 的输入值的最佳方法是什么?
问题描述
我在 Activity 中有一个按钮。当我按下这个按钮时,我想在从另一个对话框接收输入值后用输入值执行一些功能。
我在以下配置中实现了这个请求。
视图模型
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中弹出一个dialog,但是从Dialog接收任何值返回给ViewModel的流程不一致时,一般会使用Activity使用Subject订阅ViewModel等方式。
上述代码还需要将接收Activity输入值的接口一一传递给ViewModel。
我想改进这段代码,但我真的没有一个好主意。
解决方案
如果应用传递View
对 ViewModel 的引用,则该应用不遵循 MVVM 模式。如果一个应用遵循 MVVM,它的 ViewModel 层不需要知道任何关于它的 View 层的信息。
当前的问题MainViewModel
是它“告诉”视图显示对话框,并将对话框数据“获取”回自身。流程应该是相反的。MainActivity
应该是“观察”事件并将数据“提供”给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
}
主要活动
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
.
推荐阅读
- python - 带有 datetimeindex 的 Pandas get_loc 失败
- c - 从给定文件中索引单词的程序在打印某个索引时返回一个空白区域
- ar.js - AR.js 是否可以更新 gps-entity-place 的位置?
- javascript - 从数组中获取特定值并将这些值转换为另一个数组
- java - 无法在 java 中使用使用 ObjectInputStream 和 SealedObject 的 readObject()。获取运行时错误
- ios - AVPlayerItem externalMetadata 无法识别的选择器
- javascript - 如何在 Sequelize 中创建关联
- python - 我在 python 中有一个数组,我想将它转换为一维数组
- materialize - 实现 CSS 悬停效果无法正常工作
- css - mat-tab-group 显示垂直而不是水平 Angular