简体   繁体   English

如何使用 ViewModel 和 Room 从 DialogFragment 检索数据

[英]How to retrive data from DialogFragment with ViewModel and Room

I'm building an Android app that has different pages that mainly have some EditText.我正在构建一个 Android 应用程序,它有不同的页面,主要有一些 EditText。 My goal is to handle the click on the EditText and shows a DialogAlert with an EditText, then the user can put the text, click "save" and the related field in the database (I'm using Room and I've tested the queries and everything works) will be updated.我的目标是处理对 EditText 的单击并显示带有 EditText 的 DialogAlert,然后用户可以放置文本,单击“保存”和数据库中的相关字段(我正在使用 Room,并且我已经测试了查询一切正常)将被更新。 Now I was able to handle the text from the DialogFragment using interface but I don't know how to say that the text retrieved is related to the EditText that I've clicked.现在我可以使用界面处理来自 DialogFragment 的文本,但我不知道如何说检索到的文本与我单击的 EditText 相关。 What is the best approach to do this?做到这一点的最佳方法是什么? Thanks in advance for your help.在此先感谢您的帮助。

Let's take this fragment as example:让我们以这个片段为例:

class StaticInfoResumeFragment : Fragment(), EditNameDialogFragment.OnClickCallback {

private val wordViewModel: ResumeStaticInfoViewModel by viewModels {
    WordViewModelFactory((requireActivity().application as ManagementCinemaApplication).resumeStaticInfoRepo)
}

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?,
): View? {
    val root = inflater.inflate(R.layout.fragment_static_info_resume, container, false)

    wordViewModel.resumeStaticInfo.observe(viewLifecycleOwner) { words ->
        println("test words: $words")
    }

    val testView = root.findViewById<TextInputEditText>(R.id.textInputEditText800)


    testView.setOnClickListener{
        val fm: FragmentManager = childFragmentManager
        val editNameDialogFragment = EditNameDialogFragment.newInstance("Some Title")
        editNameDialogFragment.show(fm, "fragment_edit_name")
    }

    resumeStaticInfoViewModel.firstName.observe(viewLifecycleOwner, Observer {
        testView.setText(it)
    })

    return root
}

override fun onClick(test: String) {
    println("ciao test: $test")
    wordViewModel.updateFirstName(testa)
}}

Then I've the ViewModel:然后我有 ViewModel:

class ResumeStaticInfoViewModel(private val resumeStaticInfoRepo: ResumeStaticInfoRepo): ViewModel() {

val resumeStaticInfo: LiveData<ResumeStaticInfo> = resumeStaticInfoRepo.resumeStaticInfo.asLiveData()

fun updateFirstName(resumeStaticInfoFirstName: String) = viewModelScope.launch {
    resumeStaticInfoRepo.updateFirstName(resumeStaticInfoFirstName)
}
....

And the DialogFragment:和 DialogFragment:

class EditNameDialogFragment : DialogFragment() {

private lateinit var callback: OnClickCallback

interface OnClickCallback {
    fun onClick(test: String)
}

override fun onAttach(context: Context) {
    super.onAttach(context)
    try {
        callback = parentFragment as OnClickCallback
    } catch (e: ClassCastException) {
        throw ClassCastException("$context must implement UpdateNameListener")
    }
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val title = requireArguments().getString("title")
    val alertDialogBuilder: AlertDialog.Builder = AlertDialog.Builder(requireContext())
    alertDialogBuilder.setTitle(title)
    val layoutInflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
    val alertCustomView = layoutInflater.inflate(R.layout.alert_dialog_edit_item, null)
    val editText = alertCustomView.findViewById<EditText>(R.id.alert_edit)
    alertDialogBuilder.setView(alertCustomView)

    alertDialogBuilder.setPositiveButton(
        "Save",
        DialogInterface.OnClickListener { dialog, which ->
            callback.onClick(editText.text.toString())
        })
    alertDialogBuilder.setNegativeButton("No") { _: DialogInterface, _: Int -> }
    return alertDialogBuilder.create()
}

companion object {
    fun newInstance(title: String?): EditNameDialogFragment {
        val frag = EditNameDialogFragment()
        val args = Bundle()
        args.putString("title", title)
        frag.arguments = args
        return frag
    }
}

} }

Do you mean you just want to show a basic dialog for entering some text, and you want to be able to reuse that for multiple EditText s?您的意思是您只想显示一个用于输入一些文本的基本对话框,并且您希望能够为多个EditText重用它? And you want a way for the dialog to pass the result back, but also have some way of identifying which EditText it was created for in the first place?并且您想要一种让对话框将结果传回的方法,而且还需要某种方法来识别它最初是为哪个EditText创建的?

The thing about dialogs is they can end up being recreated (like if the app is destroyed in the background, and then restored when the user switches back to it) so the only real configuration you can do on it (without getting into some complexity anyway) is through its arguments , like you're doing with the title text.关于对话框的问题是它们最终可能会被重新创建(例如,如果应用程序在后台被破坏,然后在用户切换回它时恢复),因此您可以对其进行的唯一真正配置(无论如何都不会变得复杂) ) 是通过它的arguments ,就像你对标题文本所做的那样。

So one approach you could use is send some identifier parameter to newInstance , store that in the arguments, and then pass it back in the click listener.因此,您可以使用的一种方法是将一些标识符参数发送到newInstance ,将其存储在 arguments 中,然后将其传递回点击侦听器。 So you're giving the callback two pieces of data in onClick - the text entered and the reference ID originally passed in. That way, the activity can handle the ID and decide what to do with it.因此,您在onClick中为回调提供了两条数据——输入的文本和最初传入的参考 ID。这样,活动可以处理 ID 并决定如何处理它。

An easy value you could use is the resource ID of the EditText itself, the one you pass into findViewById - it's unique, and you can easily use it to set the text on the view itself.您可以使用的一个简单值是EditText本身的资源 ID,即您传递给findViewById的资源 ID - 它是唯一的,您可以轻松地使用它来设置视图本身的文本。 You're using a ViewModel here, so it should be updating automatically when you set a value in that, but in general it's a thing you could do.您在这里使用ViewModel ,因此当您在其中设置值时它应该会自动更新,但通常这是您可以做的事情。


The difficulty is that you need to store some mapping of IDs to functions in the view model, so you can handle each case.困难在于您需要在视图 model 中存储一些 ID 到函数的映射,以便您可以处理每种情况。 That's just the nature of making the dialog non-specific, but it's easier than making a dialog for each property you want to update!这只是使对话框不特定的本质,但它比为要更新的每个属性创建对话框更容易! You could make it a when block, something like:您可以将其设为when块,例如:

// you don't need the @ResId annotation but it can help you avoid mistakes!
override fun onClick(text: String, @ResId id: Int) {
    when(id) {
        R.id.coolEditText -> viewModel.setCoolText(text)
        ...
    }
} 

where you list all your cases and what to call for each of them.您在其中列出所有案例以及每个案例的要求。 You could also make a map like你也可以制作一个 map 像

val updateFunctions = mapOf<Int, (String) -> Unit>(
    R.id.coolEditText to viewModel::setCoolText
)

and then in your onClick you could call updateFunctions[id]?.invoke(text) to grab the relevant function for that EditText and call it with the data.然后在您的onClick中,您可以调用updateFunctions[id]?.invoke(text)来获取该EditText的相关 function 并使用数据调用它。 (Or use get which throws an exception if the EditText isn't added to the map, which is a design error you want to get warned about, instead of silently ignoring it which is what the null check does) (或者如果EditText未添加到 map 中,则使用get引发异常,这是您想要得到警告的设计错误,而不是默默地忽略它,这是 null 检查所做的)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用视图模型将数据从 DialogFragment 发送到 Fragment - How to send data from DialogFragment to Fragment using viewmodel 如何将数据从DialogFragment发送到DialogFragment? - How to send data from DialogFragment to DialogFragment? 如何从具有相同电子邮件地址的会议室数据库中检索数据列表 - How to retrive list of data from room database that has same email address 无法使用 Room 和协程从数据库中检索数据 - Unable to retrive data from database using Room and coroutine 如何从 firebase 中检索这些数据? - How to retrive this data from firebase? 如何在 DialogFragment 中观察 ViewModel LiveData? - How to observe ViewModel LiveData in a DialogFragment? 如何创建不调用RuntimeException即可从Room数据库访问数据的ViewModel? - How can I create a ViewModel that accesses data from a Room database without invoking a RuntimeException? Android Room:如何将来自多个 SQL 查询的数据合并到一个 ViewModel - Android Room: How to combine data from multiple SQL queries into one ViewModel Viewmodel 没有从 Android Room 更新数据,但成功插入其中 - Viewmodel doesn't update data from Android Room, but successfully insert in it 使用 ViewModel 和数据绑定显示 Room 数据库中的数据时出现问题 - Problem displaying data from Room database with ViewModel and Databinding
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM