当 DialogFragment 打开屏幕旋转变化时,Observer 被多次调用
Observer is called multiple times when DialogFragment is opened with screen rotation changes
我有一个 activity,它在 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 returns 到横向模式。
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()
}
}
}
此流程使观察者多次触发,使我的应用出现不良行为,因为实时数据结果会打开一个对话框并多次显示。
我只想在 DialogFragment 关闭后调用 postInput
方法一次。
谢谢!
LiveData
默认设置为近循环逻辑。当视图更新 LiveData
时,这会引发一些问题,然后 LiveData
将再次更新视图,从而创建无限循环。尽管您是通过激发 Android Lifecycle
重新创建您的 Activity
来间接执行此操作,并且当它重新创建时它会附加另一个观察者,从而重新发出旧值。
您有 2 个选择:
保存已在 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)
}
}
或
创建一个新的包装器 class 可以跟踪它是否已发出。
这是一个例子
接受的答案会让您将条形码包裹在一个事件中 class,这样您就可以判断它之前是否已经发出。
我有一个 activity,它在 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 returns 到横向模式。
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()
}
}
}
此流程使观察者多次触发,使我的应用出现不良行为,因为实时数据结果会打开一个对话框并多次显示。
我只想在 DialogFragment 关闭后调用 postInput
方法一次。
谢谢!
LiveData
默认设置为近循环逻辑。当视图更新 LiveData
时,这会引发一些问题,然后 LiveData
将再次更新视图,从而创建无限循环。尽管您是通过激发 Android Lifecycle
重新创建您的 Activity
来间接执行此操作,并且当它重新创建时它会附加另一个观察者,从而重新发出旧值。
您有 2 个选择:
保存已在 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)
}
}
或
创建一个新的包装器 class 可以跟踪它是否已发出。
这是一个例子
接受的答案会让您将条形码包裹在一个事件中 class,这样您就可以判断它之前是否已经发出。