如何使用 ViewModel 和 Room 从 DialogFragment 中检索数据
How to retrive data from DialogFragment with ViewModel and Room
我正在构建一个 Android 应用程序,它有不同的页面,主要有一些 EditText。我的目标是处理 EditText 上的点击并显示带有 EditText 的 DialogAlert,然后用户可以放置文本,点击“保存”和数据库中的相关字段(我正在使用 Room 并且我已经测试了查询并且一切正常)将被更新。现在我可以使用界面处理来自 DialogFragment 的文本,但我不知道如何说检索到的文本与我单击的 EditText 相关。最好的方法是什么?
预先感谢您的帮助。
我们以这个片段为例:
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)
}}
然后我有 ViewModel:
class ResumeStaticInfoViewModel(private val resumeStaticInfoRepo: ResumeStaticInfoRepo): ViewModel() {
val resumeStaticInfo: LiveData<ResumeStaticInfo> = resumeStaticInfoRepo.resumeStaticInfo.asLiveData()
fun updateFirstName(resumeStaticInfoFirstName: String) = viewModelScope.launch {
resumeStaticInfoRepo.updateFirstName(resumeStaticInfoFirstName)
}
....
和 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
}
}
}
您的意思是您只想显示一个用于输入一些文本的基本对话框,并且您希望能够将其重复用于多个 EditText
吗?你想要一种方法让对话框将结果传回,但也有一些方法来识别它最初是为哪个 EditText
创建的?
关于对话框的事情是它们最终可以被重新创建(就像如果应用程序在后台被破坏,然后当用户切换回它时恢复)所以你可以在它上面做的唯一真正的配置(没有无论如何都会变得有些复杂)是通过它的 arguments
,就像您在处理标题文本一样。
因此,您可以使用的一种方法是将一些标识符参数发送到 newInstance
,将其存储在参数中,然后将其传回点击侦听器。因此,您在 onClick
中为回调提供了两条数据 - 输入的文本和最初传入的参考 ID。这样,activity 可以处理 ID 并决定如何处理它。
您可以使用的一个简单值是 EditText
本身的资源 ID,即您传递给 findViewById
的资源 ID - 它是唯一的,您可以轻松地使用它来设置看自己。您在这里使用的是 ViewModel
,因此当您在其中设置值时它应该会自动更新,但总的来说这是您可以做的事情。
困难在于您需要在视图模型中存储一些 ID 到函数的映射,以便您可以处理每种情况。这只是制作对话框 non-specific 的本质,但它比为每个要更新的 属性 制作一个对话框更容易!您可以将其设为 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)
...
}
}
您在哪里列出所有案例以及每个案例的调用内容。你也可以制作一张像
这样的地图
val updateFunctions = mapOf<Int, (String) -> Unit>(
R.id.coolEditText to viewModel::setCoolText
)
然后在你的 onClick
中你可以调用 updateFunctions[id]?.invoke(text)
来获取那个 EditText
的相关函数并用数据调用它。 (或者使用 get
如果 EditText
没有被添加到地图,它会抛出异常,这是一个你想要得到警告的设计错误,而不是默默地忽略它,这就是 null 检查确实)
我正在构建一个 Android 应用程序,它有不同的页面,主要有一些 EditText。我的目标是处理 EditText 上的点击并显示带有 EditText 的 DialogAlert,然后用户可以放置文本,点击“保存”和数据库中的相关字段(我正在使用 Room 并且我已经测试了查询并且一切正常)将被更新。现在我可以使用界面处理来自 DialogFragment 的文本,但我不知道如何说检索到的文本与我单击的 EditText 相关。最好的方法是什么? 预先感谢您的帮助。
我们以这个片段为例:
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)
}}
然后我有 ViewModel:
class ResumeStaticInfoViewModel(private val resumeStaticInfoRepo: ResumeStaticInfoRepo): ViewModel() {
val resumeStaticInfo: LiveData<ResumeStaticInfo> = resumeStaticInfoRepo.resumeStaticInfo.asLiveData()
fun updateFirstName(resumeStaticInfoFirstName: String) = viewModelScope.launch {
resumeStaticInfoRepo.updateFirstName(resumeStaticInfoFirstName)
}
....
和 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
}
}
}
您的意思是您只想显示一个用于输入一些文本的基本对话框,并且您希望能够将其重复用于多个 EditText
吗?你想要一种方法让对话框将结果传回,但也有一些方法来识别它最初是为哪个 EditText
创建的?
关于对话框的事情是它们最终可以被重新创建(就像如果应用程序在后台被破坏,然后当用户切换回它时恢复)所以你可以在它上面做的唯一真正的配置(没有无论如何都会变得有些复杂)是通过它的 arguments
,就像您在处理标题文本一样。
因此,您可以使用的一种方法是将一些标识符参数发送到 newInstance
,将其存储在参数中,然后将其传回点击侦听器。因此,您在 onClick
中为回调提供了两条数据 - 输入的文本和最初传入的参考 ID。这样,activity 可以处理 ID 并决定如何处理它。
您可以使用的一个简单值是 EditText
本身的资源 ID,即您传递给 findViewById
的资源 ID - 它是唯一的,您可以轻松地使用它来设置看自己。您在这里使用的是 ViewModel
,因此当您在其中设置值时它应该会自动更新,但总的来说这是您可以做的事情。
困难在于您需要在视图模型中存储一些 ID 到函数的映射,以便您可以处理每种情况。这只是制作对话框 non-specific 的本质,但它比为每个要更新的 属性 制作一个对话框更容易!您可以将其设为 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)
...
}
}
您在哪里列出所有案例以及每个案例的调用内容。你也可以制作一张像
这样的地图val updateFunctions = mapOf<Int, (String) -> Unit>(
R.id.coolEditText to viewModel::setCoolText
)
然后在你的 onClick
中你可以调用 updateFunctions[id]?.invoke(text)
来获取那个 EditText
的相关函数并用数据调用它。 (或者使用 get
如果 EditText
没有被添加到地图,它会抛出异常,这是一个你想要得到警告的设计错误,而不是默默地忽略它,这就是 null 检查确实)