您好,登录后才能下订单哦!
在Android开发中,横竖屏切换是一个常见的场景。当用户旋转设备时,Activity会被销毁并重新创建,这会导致数据的丢失。为了解决这个问题,Android提供了ViewModel
组件。ViewModel
可以在Activity或Fragment的生命周期中保持数据的持久性,即使横竖屏切换也不会丢失数据。本文将详细介绍如何使用ViewModel
来实现不受横竖屏切换影响的数据持久化。
ViewModel
是Android架构组件的一部分,旨在以生命周期感知的方式存储和管理UI相关的数据。ViewModel
允许数据在配置更改(如横竖屏切换)后仍然存在,从而避免重新加载数据或重新初始化UI组件。
ViewModel
的生命周期与Activity或Fragment的生命周期不同。ViewModel
的生命周期从创建ViewModel
开始,直到关联的Activity或Fragment完全销毁(即onDestroy()
方法被调用)。这意味着,即使Activity或Fragment在横竖屏切换时被销毁并重新创建,ViewModel
仍然会保留其数据。
ViewModel
可以在配置更改时保留数据,避免重新加载数据。ViewModel
将UI逻辑与数据逻辑分离,使代码更易于维护和测试。ViewModel
自动处理生命周期事件,避免内存泄漏。首先,在项目的build.gradle
文件中添加ViewModel
的依赖:
dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
}
创建一个继承自ViewModel
的类,并在其中定义需要持久化的数据和方法。
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
private var counter: Int = 0
fun getCounter(): Int {
return counter
}
fun incrementCounter() {
counter++
}
}
在Activity中,通过ViewModelProvider
获取ViewModel
的实例,并使用它来管理数据。
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import com.example.myapp.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.counterText.text = viewModel.getCounter().toString()
binding.incrementButton.setOnClickListener {
viewModel.incrementCounter()
binding.counterText.text = viewModel.getCounter().toString()
}
}
}
在Fragment中使用ViewModel
的方式与Activity类似,只需通过ViewModelProvider
获取ViewModel
的实例。
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.myapp.databinding.FragmentMainBinding
class MainFragment : Fragment() {
private var _binding: FragmentMainBinding? = null
private val binding get() = _binding!!
private val viewModel: MyViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentMainBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.counterText.text = viewModel.getCounter().toString()
binding.incrementButton.setOnClickListener {
viewModel.incrementCounter()
binding.counterText.text = viewModel.getCounter().toString()
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
ViewModel
的实例是通过ViewModelProvider
创建的。ViewModelProvider
会根据Activity或Fragment的生命周期来管理ViewModel
的实例。当Activity或Fragment第一次请求ViewModel
时,ViewModelProvider
会创建一个新的ViewModel
实例。如果Activity或Fragment在配置更改后重新创建,ViewModelProvider
会返回之前创建的ViewModel
实例。
ViewModel
的实例存储在ViewModelStore
中。ViewModelStore
是一个与Activity或Fragment关联的对象,用于存储ViewModel
的实例。当Activity或Fragment被销毁时,ViewModelStore
会保留ViewModel
的实例,直到Activity或Fragment完全销毁。
当Activity或Fragment完全销毁时(即onDestroy()
方法被调用),ViewModelStore
会被清除,ViewModel
的实例也会被销毁。此时,ViewModel
的onCleared()
方法会被调用,开发者可以在此方法中释放资源或执行清理操作。
class MyViewModel : ViewModel() {
override fun onCleared() {
super.onCleared()
// 释放资源或执行清理操作
}
}
在某些情况下,即使ViewModel
可以在配置更改时保留数据,但在进程被系统杀死后,ViewModel
的数据仍然会丢失。为了解决这个问题,可以使用SavedStateHandle
来保存和恢复ViewModel
的状态。
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
class MyViewModel(private val state: SavedStateHandle) : ViewModel() {
private val COUNTER_KEY = "counter"
fun getCounter(): Int {
return state.get<Int>(COUNTER_KEY) ?: 0
}
fun incrementCounter() {
val currentCounter = state.get<Int>(COUNTER_KEY) ?: 0
state.set(COUNTER_KEY, currentCounter + 1)
}
}
在Activity或Fragment中,可以通过ViewModelProvider
的构造函数传递SavedStateHandle
。
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.SavedStateViewModelFactory
import com.example.myapp.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel: MyViewModel by viewModels {
SavedStateViewModelFactory(application, this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.counterText.text = viewModel.getCounter().toString()
binding.incrementButton.setOnClickListener {
viewModel.incrementCounter()
binding.counterText.text = viewModel.getCounter().toString()
}
}
}
LiveData
是一个可观察的数据持有者,它可以与ViewModel
结合使用,以实现数据的自动更新。当LiveData
中的数据发生变化时,UI组件会自动更新。
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
private val _counter = MutableLiveData<Int>()
val counter: LiveData<Int> get() = _counter
init {
_counter.value = 0
}
fun incrementCounter() {
_counter.value = (_counter.value ?: 0) + 1
}
}
在Activity或Fragment中,可以通过观察LiveData
来更新UI。
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import com.example.myapp.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel.counter.observe(this, Observer { count ->
binding.counterText.text = count.toString()
})
binding.incrementButton.setOnClickListener {
viewModel.incrementCounter()
}
}
}
ViewModel
可以与Room
数据库结合使用,以实现数据的持久化存储。Room
是Android提供的一个SQLite对象映射库,它可以简化数据库操作。
首先,定义实体类和DAO接口。
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "user_table")
data class User(
@PrimaryKey(autoGenerate = true) val id: Int,
val name: String,
val age: Int
)
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
@Dao
interface UserDao {
@Insert
suspend fun insert(user: User)
@Query("SELECT * FROM user_table")
fun getAllUsers(): LiveData<List<User>>
}
然后,创建数据库类。
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class UserDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
@Volatile
private var INSTANCE: UserDatabase? = null
fun getDatabase(context: Context): UserDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
UserDatabase::class.java,
"user_database"
).build()
INSTANCE = instance
instance
}
}
}
}
最后,在ViewModel
中使用Room
数据库。
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class UserViewModel(application: Application) : AndroidViewModel(application) {
private val repository: UserRepository
val allUsers: LiveData<List<User>>
init {
val userDao = UserDatabase.getDatabase(application).userDao()
repository = UserRepository(userDao)
allUsers = repository.allUsers
}
fun insert(user: User) = viewModelScope.launch {
repository.insert(user)
}
}
在Activity或Fragment中,可以通过ViewModel
来操作数据库。
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import com.example.myapp.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val userViewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
userViewModel.allUsers.observe(this, Observer { users ->
// 更新UI
})
binding.addUserButton.setOnClickListener {
val user = User(name = "John", age = 25)
userViewModel.insert(user)
}
}
}
ViewModel
是Android开发中一个非常重要的组件,它可以帮助开发者在横竖屏切换时保持数据的持久性。通过ViewModel
,开发者可以将UI逻辑与数据逻辑分离,使代码更易于维护和测试。此外,ViewModel
还可以与LiveData
、Room
等组件结合使用,以实现更复杂的功能。
在实际开发中,开发者应根据具体需求选择合适的ViewModel
使用方式,并结合其他架构组件,构建出高效、稳定的Android应用。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。