我有一个应用程序,我将视图模型绑定到主活动生命周期,并且我确实根据调用的生命周期增加了一个计数器,但我无法增加计数器变量,不管是什么原因,谢谢
- 这是我的视图模型类
class CounterViewModel : ViewModel(), DefaultLifecycleObserver {
private var onCreateCounter = 0
private var onStartCounter = 0
private var onResumeCounter = 0
// This class defines the ViewModel which keeps track of the number of times onCreate(), onStart() and onResume() have been called.
companion object {
private const val TAG = "CounterViewModel"
}
// TODO :
// Create variables to keep a track of the number of times onCreate(), onStart() and onResume() have been called.
// To keep track of each count, define two variables as specified below.
// Define a private variable of type MutableLiveData that can only be modified within the ViewModel class.
// Define an internal/public variable of type LiveData that can be accessed externally by the UI/fragment but cannot be modified.
// Use a backing property to specify the getter function for the internal/public variable
// Refer to the link below for a more detailed explanation/example
// https://developer.android.com/codelabs/basic-android-kotlin-training-viewmodel#4
private val _onStartMutableLiveData : MutableLiveData<Int> = MutableLiveData(onStartCounter)
val onStartLiveData : LiveData<Int> get() = _onStartMutableLiveData
private val _onCreateMutableLiveData : MutableLiveData<Int> = MutableLiveData(onCreateCounter)
val onCreateLiveData : LiveData<Int> get() = _onCreateMutableLiveData
private val _onResumeMutableLiveData : MutableLiveData<Int> = MutableLiveData(onResumeCounter)
val onResumeLiveData : LiveData<Int> get() = _onResumeMutableLiveData
val onCreateProperty : LiveData<Int>
get() {
return onCreateLiveData
}
val onStartProperty : LiveData<Int>
get() {
return onStartLiveData
}
val onResumeProperty : LiveData<Int>
get() {
return onResumeLiveData
}
internal fun bindToActivityLifecycle(mainActivity: MainActivity) {
// TODO :
// Add the current instance of CounterViewModel as a LifeCycleObserver to the MainActivity
// Use the addObserver function
mainActivity.lifecycle.addObserver(this)
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
// Update the appropriate count variable
Log.i(TAG,"Entered onResume")
onResumeCounter++
_onResumeMutableLiveData.value = onResumeCounter
}
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
// Update the appropriate count variable
Log.i(TAG,"Entered onCreate")
onCreateCounter++
_onCreateMutableLiveData.value = onCreateCounter
}
override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
// Update the appropriate count variable
Log.i(TAG,"Entered onStart")
onStartCounter++
_onStartMutableLiveData.value = onStartCounter
}
}
**片段代码
class FirstFragment : Fragment() {
/** Binding to XML layout */
private lateinit var binding: FirstFragmentBinding
// Create a variable of type CounterViewModel to keep track of counts
private lateinit var viewModel: CounterViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Use the provided binding object to inflate the layout.
binding = FirstFragmentBinding.inflate(inflater, container, false)
// Update ActionBar label to distinguish which Fragment is displayed
(requireActivity() as AppCompatActivity).supportActionBar?.title = this.javaClass.simpleName
// Set onClickListener to navigate to the second fragmant from the first
binding.fab.setOnClickListener {
findNavController().navigate(FirstFragmentDirections.actionFirstFragmentToSecondFragment())
}
// Return the root view.
return binding.root
}
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// TODO:
// Initialize CounterViewModel instance
viewModel = ViewModelProvider(this)[CounterViewModel::class.java]
// TODO:
// Use binding to display initial counts
binding.onCreate.text = "onCreate Called : ${viewModel.onCreateLiveData.value}"
binding.onStart.text = "onStart Called : ${viewModel.onStartLiveData.value}"
binding.onResume.text = "onResume Called : ${viewModel.onResumeLiveData.value}"
// The function below updates the counts over time
beginObservingCounter()
}
@SuppressLint("SetTextI18n")
private fun beginObservingCounter() {
// TODO:
// Register observers for each of the count variables
// In the body of the observe function, update the text to be displayed by using the binding
viewModel.onStartLiveData.observe(viewLifecycleOwner){ counter ->
binding.onStart.text = "onStart Called Again $counter"
}
viewModel.onCreateLiveData.observe(viewLifecycleOwner){ counter ->
binding.onCreate.text = "onCreate Called Again $counter"
}
viewModel.onResumeLiveData.observe(viewLifecycleOwner){ counter ->
binding.onResume.text = "onResume Called Again $counter"
}
}
}
您在评论中提到,当您旋转时,会调用init块-哪个init块?旋转屏幕应该会给你一个相同的ViewModel
实例,它的所有状态都完好无损,这就是它们的重点。也许你初始化它们的方式不对,也许你创建了另一个副本,并从中观察LiveData
,而不是实际观察你生命周期并递增的实例?
值得一提的是,你的代码在这样的Activity
中对我来说很好:
val counterViewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
counterViewModel.bindToActivityLifecycle(this)
// onResumeProperty works too since it's the same thing!
counterViewModel.onResumeLiveData.observe(this) { count ->
Toast.makeText(this, "Resumes: $count", Toast.LENGTH_SHORT).show()
}
}
每次onResume
发生时,我都会得到一个Toast——从技术上讲,这种情况发生得更频繁,因为它在旋转时首先观察旧数据,然后在再次点击onResume
时获得新值,但它确实有效!所以我会确保你处理正确的实例
因此,虽然operator fun inc()
的定义用于++
,但它们不起相同的作用,0.inc()
有效,而0++
无效。事实证明,inc
所做的只是返回值加1(请参阅文档(,++
调用inc
,但也设置新值。因此,您可以更改为使用++
或进行onStartCounter = onStartCounter.inc()