[转]Android ViewModel 的使用

使用ViewModel保持数据状态
本文介绍如何使用Android的ViewModel组件来在横竖屏切换时保持数据状态,避免数据丢失或重复初始化。通过示例代码展示了ViewModel在Activity生命周期中的应用,确保即使在屏幕旋转导致Activity重建时,计时器的时间也能得到正确保留。

0 原文学习

https://www.jianshu.com/p/721cdcdf11b2

1. ViewModel 好处

目前看到的好处是:横竖屏切换的时候,ViewModel 可以有效保留数据状态。防止数据初始化或丢失

2. 代码示例

2.1 调用示例
package com.fadi.su.viewmodeldemo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;

import android.os.Bundle;
import android.os.SystemClock;
import android.widget.Chronometer;

public class MainActivity extends AppCompatActivity {

    private final static boolean GOOD = true;

    private Chronometer chronometer;

    private  ChronometerViewModel mViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initValues();

        if (GOOD) {
            newStartTime();
        } else {
            oldStartTime();
        }
    }

    private void initView() {
        chronometer = findViewById(R.id.chronometer);
    }

    private void initValues() {
    }

    /**
     * 这样的写法,只有横竖屏切换,onCreate 周期就重新调用,导致计数每次都重头开始
     */
    private void oldStartTime() {
        long startTime = SystemClock.elapsedRealtime();
        chronometer.setBase(startTime);
        chronometer.start();
    }

    /**
     * 横竖屏切换就很正常了
     * ViewModel 可以在横竖屏变化的时候保存数据,即数据保留的生命周期
     *
     * 例如一个Activity由于旋转而被销毁,但是ViewModel并不会销毁,新创建的Activity的实例仅仅是重新关联到已经存在的ViewModel
     */
    private void newStartTime() {
        // 一个ViewModel的创建总是和一个作用域(一个 Fragment/Activity)有关,并且只要这个作用域存活,那么这个ViewModel会被一直保留。
        mViewModel = ViewModelProviders.of(this).get(ChronometerViewModel.class);

        if (mViewModel.getStartTime() == null) {
            long startTime = SystemClock.elapsedRealtime();
            mViewModel.setStartTime(startTime);
        }

        chronometer.setBase(mViewModel.getStartTime());
        chronometer.start();
    }

}

2.2 示例布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Chronometer
        android:id="@+id/chronometer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
2.3 ViewModel 对象
package com.fadi.su.viewmodeldemo;

import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModel;

/**
 * ViewModel的唯一的作用是管理UI的数据
 */
public class ChronometerViewModel extends ViewModel {


    @NonNull
    private Long startTime;

    @NonNull
    public Long getStartTime() {
        return startTime;
    }

    public void setStartTime(@NonNull Long startTime) {
        this.startTime = startTime;
    }

}

2.4 build.gradle 需要配置
dependencies {
    implementation 'android.arch.lifecycle:extensions:1.1.1'
}
### AndroidViewModel 使用方法 AndroidViewModelAndroid 架构组件 ViewModel 的一个子类,主要用于在 Android 应用中保存和管理与用户界面相关的数据。它在配置更改(如屏幕旋)时能够保持数据的稳定性,并帮助开发者解耦 UI 和业务逻辑。AndroidViewModel 与普通的 ViewModel 的主要区别在于,它提供了对 Application 上下文的访问,因此适用于需要依赖 Application 的场景,例如访问系统服务或全局资源。 #### 1. 创建 AndroidViewModel 子类 首先,开发者需要创建一个继承自 `AndroidViewModel` 的类,并在其中定义所需的 UI 数据和业务逻辑。例如,以下是一个用于管理天气数据的 AndroidViewModel 实现: ```kotlin class WeatherViewModel(application: Application) : AndroidViewModel(application) { private val _weatherData = MutableLiveData<String>() val weatherData: LiveData<String> get() = _weatherData fun fetchWeather(city: String) { // 模拟网络请求 viewModelScope.launch { val result = withContext(Dispatchers.IO) { // 假设调用天气 API 获取数据 "Weather in $city: 25°C" } _weatherData.postValue(result) } } } ``` #### 2. 在 Activity 或 Fragment 中使用 AndroidViewModel 接下来,在 Activity 或 Fragment 中通过 `ViewModelProvider` 获取 ViewModel 实例,并观察其数据变化。以下是使用 Kotlin 和 Jetpack Compose 的示例代码: ```kotlin class MainActivity : ComponentActivity() { private lateinit var weatherViewModel: WeatherViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) weatherViewModel = ViewModelProvider(this)[WeatherViewModel::class.java] setContent { var weatherText by remember { mutableStateOf("点击按钮获取天气信息") } Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Button(onClick = { weatherViewModel.fetchWeather("Beijing") }) { Text(text = "获取北京天气") } Text(text = weatherText) } // 观察 ViewModel 中的 LiveData weatherViewModel.weatherData.observe(this@MainActivity) { data -> weatherText = data } } } } ``` #### 3. 生命周期感知与数据持久性 AndroidViewModel 的核心优势在于其生命周期感知能力。当用户旋屏幕或设备配置发生变化时,ViewModel 会保留数据,而无需重新请求网络或重新计算。通过 `observe` 方法,UI 可以自动更新以反映最新的数据状态。 #### 4. 使用 Application 上下文 由于 AndroidViewModel 提供了对 Application 上下文的访问,开发者可以在 ViewModel 中安全地访问系统服务或全局资源。例如,可以通过 `getApplication<Application>().contentResolver` 访问内容解析器,或者使用 `getApplication<Application>().getSystemService(Context.LOCATION_SERVICE)` 获取位置服务。 #### 5. 避免内存泄漏 AndroidViewModel 通过持有 Application 上下文来避免内存泄漏问题。普通 ViewModel 可能会因持有 Activity 上下文而导致内存泄漏,而 AndroidViewModel 通过使用 Application 上下文确保了更安全的生命周期管理。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值