如何处理 Android 中的配置更改?
有时,Android 设备会在应用程序运行时进行配置更改。当设备进行配置更改时,所有活动和片段都会重新创建。这种在配置更改时重新启动应用程序有助于应用程序通过自动重新加载与新设备配置匹配的应用程序替代资源来适应新配置。在发生这种活动和片段的重新创建时,需要恢复数据和 UI。这样做的传统方法是使用包并处理onSavedInstanceStae()的回调。请参阅如何使用捆绑包恢复 Android 中更改的配置的数据?。现在看看下图,如果处理不当,数据在配置更改期间如何丢失。因此,在本次讨论中,我们演示了如何在配置更改后恢复数据和更新 UI。
Note: This discussion is implemented in the Kotlin programming language.
android中处理配置变化的步骤
第 1 步:创建空活动 Android Studio 项目
创建一个空的活动 Android Studio 项目并选择 Kotlin 作为编程语言。参考安卓 |如何在 Android Studio 中创建/启动新项目?
第 2 步:添加所需的依赖项
本项目需要 Lifecycle 扩展、ViewModels 和 Livedata 的依赖。因此,将以下依赖项添加到应用程序级 Gradle 文件中。
// lifecycle_version and architecture version may vary
def lifecycle_version = “2.3.1”
def arch_version = “2.1.0”
// ViewModel
implementation “androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version”
// LiveData
implementation “androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version”
// Lifecycles only (without ViewModel or LiveData)
implementation “androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version”
// architecture Lifecycle extensions
implementation “androidx.lifecycle:lifecycle-extensions:$arch_version”
第 3 步:使用 activity_main.xml 文件
应用程序的主要布局包含一个按钮和一个 TextView。要实现相同的调用,请在activity_main.xml文件中调用以下代码。
XML
Kotlin
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
// number to increment and show on UI
var number = 0
// function when called increments the value of number
fun addNumber(): Int = number++
}
Kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// create instance of the viewModel of the Custom MyViewModel for the activity MainActivity.kt
val myViewModel: MyViewModel = ViewModelProvider(this).get(MyViewModel::class.java)
// create instances of the UI elements
val button: Button = findViewById(R.id.button)
val textView: TextView = findViewById(R.id.textView)
textView.text = myViewModel.number.toString()
button.setOnClickListener {
// trigger the increment
// function to increment the value
myViewModel.incrementNumber()
// set the updated value of number to the TextView
textView.text = myViewModel.number.toString()
}
}
}
输出界面:
第 4 步:了解整个活动期间 ViewModel 的作用域
- 通过参考下图,可以看出,在获取 ViewModel 时,ViewModel 的对象范围为传递给 ViewModelProvider 的生命周期所有者。 ViewModel 对象在生命周期所有者的整个生命周期中都保留在内存中。这里的生命周期所有者是 MainActivity.kt,它有自己的生命周期。
- 在活动的情况下,当活动完成时,ViewModel 对象的范围将被销毁。在 Fragment 的情况下,当它分离时。
- 系统调用onCreate()方法时创建的 ViewModel 对象。在整个活动生命周期中,它可能会被多次调用。例如当设备旋转时。 ViewModel 对象在第一次请求时仍然存在,直到活动完成并销毁。
第 5 步:为活动创建 ViewModel
ViewModel 类继承了 ViewModel 作为超类。并且在其中创建了所需的数据成员和成员函数,其中所有数据成员和函数的范围在活动的整个生命周期中保持不变。要实现 ViewModel,请创建一个名为 MyViewModel.kt 的类并调用以下代码。
科特林
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
// number to increment and show on UI
var number = 0
// function when called increments the value of number
fun addNumber(): Int = number++
}
第 6 步:使用 MainActivity.kt
在MainActivity.kt文件中,ViewModel 的对象是使用生命周期所有者的 ViewModelProvider 创建的。这里的生命周期所有者是 MainAactivity.kt 文件。要实现相同的调用,请在MainActivity.kt文件中调用以下代码。
科特林
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// create instance of the viewModel of the Custom MyViewModel for the activity MainActivity.kt
val myViewModel: MyViewModel = ViewModelProvider(this).get(MyViewModel::class.java)
// create instances of the UI elements
val button: Button = findViewById(R.id.button)
val textView: TextView = findViewById(R.id.textView)
textView.text = myViewModel.number.toString()
button.setOnClickListener {
// trigger the increment
// function to increment the value
myViewModel.incrementNumber()
// set the updated value of number to the TextView
textView.text = myViewModel.number.toString()
}
}
}
输出: