【问题标题】:Live Data Observer On Button Click when screen rotataedLive Data Observer On 按钮 屏幕旋转时单击
【发布时间】: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)
}

【问题讨论】:

    标签: android kotlin android-livedata


    【解决方案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

        【讨论】:

          猜你喜欢
          • 2011-05-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-15
          • 1970-01-01
          • 2020-06-07
          • 2023-03-28
          • 1970-01-01
          相关资源
          最近更新 更多