Android ViewModel创建不受横竖屏切换影响怎么实现

发布时间:2023-03-08 10:43:45 作者:iii
来源:亿速云 阅读:147

Android ViewModel创建不受横竖屏切换影响怎么实现

在Android开发中,横竖屏切换是一个常见的场景。当用户旋转设备时,Activity会被销毁并重新创建,这会导致数据的丢失。为了解决这个问题,Android提供了ViewModel组件。ViewModel可以在Activity或Fragment的生命周期中保持数据的持久性,即使横竖屏切换也不会丢失数据。本文将详细介绍如何使用ViewModel来实现不受横竖屏切换影响的数据持久化。

1. ViewModel简介

ViewModel是Android架构组件的一部分,旨在以生命周期感知的方式存储和管理UI相关的数据。ViewModel允许数据在配置更改(如横竖屏切换)后仍然存在,从而避免重新加载数据或重新初始化UI组件。

1.1 ViewModel的生命周期

ViewModel的生命周期与Activity或Fragment的生命周期不同。ViewModel的生命周期从创建ViewModel开始,直到关联的Activity或Fragment完全销毁(即onDestroy()方法被调用)。这意味着,即使Activity或Fragment在横竖屏切换时被销毁并重新创建,ViewModel仍然会保留其数据。

1.2 ViewModel的优势

2. ViewModel的基本使用

2.1 添加依赖

首先,在项目的build.gradle文件中添加ViewModel的依赖:

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
}

2.2 创建ViewModel

创建一个继承自ViewModel的类,并在其中定义需要持久化的数据和方法。

import androidx.lifecycle.ViewModel

class MyViewModel : ViewModel() {
    private var counter: Int = 0

    fun getCounter(): Int {
        return counter
    }

    fun incrementCounter() {
        counter++
    }
}

2.3 在Activity中使用ViewModel

在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()
        }
    }
}

2.4 在Fragment中使用ViewModel

在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
    }
}

3. ViewModel的工作原理

3.1 ViewModel的创建

ViewModel的实例是通过ViewModelProvider创建的。ViewModelProvider会根据Activity或Fragment的生命周期来管理ViewModel的实例。当Activity或Fragment第一次请求ViewModel时,ViewModelProvider会创建一个新的ViewModel实例。如果Activity或Fragment在配置更改后重新创建,ViewModelProvider会返回之前创建的ViewModel实例。

3.2 ViewModel的存储

ViewModel的实例存储在ViewModelStore中。ViewModelStore是一个与Activity或Fragment关联的对象,用于存储ViewModel的实例。当Activity或Fragment被销毁时,ViewModelStore会保留ViewModel的实例,直到Activity或Fragment完全销毁。

3.3 ViewModel的销毁

当Activity或Fragment完全销毁时(即onDestroy()方法被调用),ViewModelStore会被清除,ViewModel的实例也会被销毁。此时,ViewModelonCleared()方法会被调用,开发者可以在此方法中释放资源或执行清理操作。

class MyViewModel : ViewModel() {
    override fun onCleared() {
        super.onCleared()
        // 释放资源或执行清理操作
    }
}

4. ViewModel的高级用法

4.1 使用SavedStateHandle保存状态

在某些情况下,即使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()
        }
    }
}

4.2 使用LiveData与ViewModel结合

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()
        }
    }
}

4.3 使用ViewModel与Room数据库结合

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)
        }
    }
}

5. 总结

ViewModel是Android开发中一个非常重要的组件,它可以帮助开发者在横竖屏切换时保持数据的持久性。通过ViewModel,开发者可以将UI逻辑与数据逻辑分离,使代码更易于维护和测试。此外,ViewModel还可以与LiveDataRoom等组件结合使用,以实现更复杂的功能。

在实际开发中,开发者应根据具体需求选择合适的ViewModel使用方式,并结合其他架构组件,构建出高效、稳定的Android应用。

推荐阅读:
  1. 一个不错的loading效果
  2. android定时器

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

android viewmodel

上一篇:Docker如何配置WebSSH

下一篇:Oracle数据库表被锁怎么查询和解锁

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》