当 DialogFragment 通过屏幕旋转更改打开时,多次调用观察者
Posted
技术标签:
【中文标题】当 DialogFragment 通过屏幕旋转更改打开时,多次调用观察者【英文标题】:Observer is called multiple times when DialogFragment is opened with screen rotation changes 【发布时间】:2021-12-27 03:41:19 【问题描述】:我有一个在 OnCreate 中为 ViewModel 中的 MutableLiveData 变量实现观察者的活动。
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
...
subscribeDialogFragmentManualInput()
private fun subscribeDialogFragmentManualInput()
this.sharedViewModel.inputBarcode.observe(this) inputValue ->
postInput(inputValue)
我的 Activity 始终处于横向模式(Manifest 中的默认模式),当按下按钮时,DialogFragment 会打开并将旋转更改为纵向,当它关闭时,Activity 会返回横向模式。
private fun showInvoiceInputDialog()
val inputDialog = InvoiceInputDialogFragment
val transaction = supportFragmentManager.beginTransaction()
inputDialog.show(transaction, InvoiceInputDialogFragment.TAG)
class InvoiceInputDialogFragment : DialogFragment()
lateinit var binding: DialogFragmentInvoiceInputBinding
private val sharedViewModel by sharedViewModel<ManualInvoiceInputViewModel>()
private var invoiceInput: String = ""
...
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View
setStyle(
STYLE_NORMAL,
R.style.FullScreenDialog
)
binding = DataBindingUtil.inflate(
inflater,
R.layout.dialog_fragment_invoice_input,
container,
false
)
return binding.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
super.onViewCreated(view, savedInstanceState)
...
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setViews()
override fun onDismiss(dialog: DialogInterface)
super.onDismiss(dialog)
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
if(invoiceInput.isNotEmpty())
sharedViewModel.sendInputInvoice(invoiceInput)
private fun setViews()
binding.btConfirmInput.setOnClickListener
invoiceInput = binding.scannerManualInput.text
dismiss()
此流程使观察者多次触发,使我的应用程序出现不良行为,因为 livedata 结果打开一个对话框并多次显示。
我只想在 DialogFragment 关闭后调用一次postInput
方法。
谢谢!
【问题讨论】:
您能帮忙附上sharedViewModel.inputBarcode.postValue()
或sharedViewModel.inputBarcode.setValue()
的代码吗?并确保那些没有被多次触发
【参考方案1】:
LiveData
默认设置为近似循环逻辑。当视图更新LiveData
时,这会引发一些问题,LiveData
然后会想要再次更新视图,从而创建一个无限循环。尽管您是通过激发 android Lifecycle
重新创建您的 Activity
来间接做到这一点的,但当它重新创建时,它会附加另一个观察者,从而重新发出旧值。
你有两个选择:
保存对话框已在 savedInstanceState Bundle
中调用的事实
overide fun onSaveInstanceState(savedInstanceState : Bundle?)
// Save the user's current game state
savedInstanceState.putBoolean("dialogCausedRecreate", dialogWasCreated);
super.onSaveInstanceState(savedInstanceState);
//in onCreate
this.sharedViewModel.inputBarcode.observe(this) inputValue ->
if(!savedInstanceState.getBoolean("dialogCausedRecreate",false))
postInput(inputValue)
或
创建一个新的包装类,它可以跟踪它是否被发出。 这是一个例子 LiveData prevent receive the last value when start observing
接受的答案将让您将条形码包装在 Event 类中,这样您就可以判断它之前是否已经发出过。
【讨论】:
谢谢,我决定使用包装类,它正在工作以上是关于当 DialogFragment 通过屏幕旋转更改打开时,多次调用观察者的主要内容,如果未能解决你的问题,请参考以下文章
旋转时调用 DatePickerDialog onDateSet