Android Jetpack 之 ViewModel

138 阅读2分钟

定义:

在 Android 中,ViewModel 的作用就是在 UI 控制器( 如 Activity、Fragment)的生命周期中保存和管理 UI 相关的数据。ViewModel 保存的数据在配置更改(如屏幕旋转)后会依然存在,不会丢失。

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据

ViewModel的生命周期

image.png

优点:

  1. Activity发生屏幕旋转数据保留
  2. ViewModel + LiveData 实现 Activity 的多个 Fragment 之间共享数据
public class UserViewModel extends ViewModel {

    private MutableLiveData<Integer> scoreData;

    public MutableLiveData<Integer> getScoreData() {
        if(scoreData == null){
            scoreData = new MutableLiveData<>();
        }
        return scoreData;
    }
}
class FragmentA : Fragment() {

    private lateinit var userViewModel: UserViewModel

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        activity?.also {
            userViewModel = ViewModelProviders.of(it).get(UserViewModel::class.java)
        }
        return inflater.inflate(R.layout.fragment_a, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        userViewModel.scoreData.observe(viewLifecycleOwner, Observer<Int> {
            textView1.text = it.toString()
        })
    }
}
class FragmentB : Fragment() {
    private lateinit var userViewModel: UserViewModel

    private var num = 0;

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        activity?.also {
            userViewModel = ViewModelProviders.of(it).get(UserViewModel::class.java)
        }
        return inflater.inflate(R.layout.fragment_b, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        textView1.setOnClickListener {
            num++
            userViewModel.scoreData.postValue(num)
        }
        userViewModel.scoreData.observe(viewLifecycleOwner, Observer<Int> {
            textView2.text = it.toString()
        })
    }
}

面试题

  1. 为什么Activity旋转屏幕后ViewModel可以恢复数据

ViewModel 出现之前,Activity 可以使用 onSaveInstanceState() 方法保存,然后从 onCreate() 中的 Bundle 恢复数据,但此方法仅适合可以序列化再反序列化的少量数据(IPC 对 Bundle 有 1M 的限制),而不适合数量可能较大的数据。

当Activity首次创建时,它会请求一个ViewModel实例,通常是通过 ViewModelProvider 进行的。这个Provider负责实例化 ViewModel 对象,并确保在Activity或Fragment的生命周期内这些对象保持不变。如果在屏幕旋转等配置更改后Activity或Fragment被销毁并重新创建,ViewModelProvider会返回同一个ViewModel实例而不是创建一个新的实例,从而实现了数据的保留与恢复‌。

当Activity销毁时,系统会通过 onRetainNonConfigurationInstance() 方法将 ViewModelStore 转化为NonConfigurationInstances对象,并在Activity重建时通过 getLastNonConfigurationInstance() 方法恢复mViewModelStore实例对象,进而根据对应的key拿到销毁前对应的ViewModel实例。这种方式确保了即使在屏幕旋转等配置更改的情况下,ViewModel中的数据也能得到恢复‌。