Live Data Observer On 按钮 屏幕旋转时单击

Posted

技术标签:

【中文标题】Live Data Observer On 按钮 屏幕旋转时单击【英文标题】:Live Data Observer On Button Click when screen rotataed 【发布时间】:2021-02-26 10:26:54 【问题描述】:

我想知道按钮何时点击片段并更新 MainActivity。这段代码工作正常,但是当屏幕旋转由于再次调用 Activity LifeCycle OnCreate 和 viewModel.nav.observe 再次调用新值 true,但我希望它被称为 only onButton 点击​​。 我需要的是 onClick 值将设置为 true 然后 false,所以我只知道按钮何时单击而不是屏幕旋转。 或者通过其他方式知道在片段中单击了按钮。

我怎样才能做到这一点?

片段

class Fragment1 : Fragment() 

    companion object 
        fun newInstance() = Fragment1()
    

    private lateinit var viewModel: SharedViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 
        return inflater.inflate(R.layout.fragment_1, container, false)
    

    override fun onActivityCreated(savedInstanceState: Bundle?) 
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
        
        buttonNextF1.setOnClickListener 
            viewModel.nav.value = true
        
    

主活动

class MainActivity : AppCompatActivity() 
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val viewModel = ViewModelProvider(this).get(SharedViewModel::class.java)

        var fragment1 = Fragment1.newInstance()
        navigateToFragment(fragment1)

        viewModel.nav.observe(this, 
            Log.d("DTAG", "Status: $it")
        )
    

    private fun navigateToFragment(fragment: Fragment) 

        val fragmentTransaction = supportFragmentManager.beginTransaction()
        fragmentTransaction.addToBackStack(null)
        fragmentTransaction.replace(R.id.mainFrame, fragment)
        fragmentTransaction.commit()

    

视图模型

class SharedViewModel : ViewModel() 
    
    var nav = MutableLiveData(false)

【问题讨论】:

【参考方案1】:

您可以使用SingleLiveEvent 来实现您的目标,因为:

您只想通知事件(点击片段上的按钮)一次 只有一个观察者 (MainActivity) 在 LiveData 上观察

第 1 步:创建 SingleLiveEvent.kt 文件

class SingleLiveEvent<T> : MutableLiveData<T?>() 
    private val mPending = AtomicBoolean(false)

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T?>) 
        if (hasActiveObservers()) 
            Log.w(
                TAG,
                "Multiple observers registered but only one will be notified of changes."
            )
        
        // Observe the internal MutableLiveData
        super.observe(owner, Observer  t ->
            if (mPending.compareAndSet(true, false)) 
                observer.onChanged(t)
            
        )
    

    @MainThread
    override fun setValue(t: T?) 
        mPending.set(true)
        super.setValue(t)
    

    /**
     * Used for cases where T is Void, to make calls cleaner.
     */
    @MainThread
    fun call() 
        value = null
    

    companion object 
        private const val TAG = "SingleLiveEvent"
    

第 2 步:在 SharedViewModel 中

class SharedViewModel : ViewModel() 
    var nav = SingleLiveEvent<Boolean>()

第 3 步:在 MainActivity 中

viewModel.nav.observe(this, Observer 
    Log.d("DTAG", "Status: $it")
)

【讨论】:

【参考方案2】:

我不喜欢这个解决方案,但this code lab 说,您应该将“导航处理”事件发布回视图模型。

查看模型实现:

interface MyViewModel 
    val navigationEvent: LiveData<Unit?>
    
    fun onNavigationButtonClicked()
    fun onNavigationDone()


class MyViewModelImpl : ViewModel(), MyViewModel 
    
    override val navigationEvent = MutableLiveData<Unit?>()

    override fun onNavigationButtonClicked() 
        navigationEvent.value = Unit
    

    override fun onNavigationDone() 
        navigationEvent.value = null
    

查看模型使用情况

vm.navigationEvent.observe(lifecycleOwner,  event ->
    // check event is not handled yet
    event ?: return@observe
    // make transition
    findNavController().navigate(direction)
    // notify view model navigation event is handled
    vm.onNavigationDone()
)

【讨论】:

【参考方案3】:

只需使用saveStateViewMode,文档here

【讨论】:

以上是关于Live Data Observer On 按钮 屏幕旋转时单击的主要内容,如果未能解决你的问题,请参考以下文章

如何将.live()转换为.on()

JavaScript--- .bind() .live() .delegate() .on()的区别

jQuery中.bind() .live() .delegate() .on()的比较

on()live()delegate()bind()的比较

jQuery中.bind() .live() .delegate() .on()的区别

谈 jquery中.band() .live() .delegate() .on()的区别