ViewModel

作者: JamesYang1624 | 来源:发表于2021-04-28 12:35 被阅读0次

简介

ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续留存。

Android 框架可以管理界面控制器(如 Activity 和 Fragment)的生命周期。Android 框架可能会决定销毁或重新创建界面控制器,以响应完全不受您控制的某些用户操作或设备事件。

如果系统销毁或重新创建界面控制器,则存储在其中的任何瞬态界面相关数据都会丢失。例如,应用可能会在它的某个 Activity 中包含用户列表。为配置更改重新创建 Activity 后,新 Activity 必须重新提取用户列表。对于简单的数据,Activity 可以使用onSaveInstanceState()方法从onCreate()中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。

另一个问题是,界面控制器经常需要进行可能需要一些时间才能返回的异步调用。界面控制器需要管理这些调用,并确保系统在其销毁后清理这些调用以避免潜在的内存泄漏。此项管理需要大量的维护工作,并且在为配置更改重新创建对象的情况下,会造成资源的浪费,因为对象可能需要重新发出已经发出过的调用。

诸如 Activity 和 Fragment之类的界面控制器主要用于显示界面数据、对用户操作做出响应或处理操作系统通信(如权限请求)。如果要求界面控制器也负责从数据库或网络加载数据,那么会使类越发膨胀。为界面控制器分配过多的责任可能会导致单个类尝试自己处理应用的所有工作,而不是将工作委托给其他类。以这种方式为界面控制器分配过多的责任也会大大增加测试的难度。

从界面控制器逻辑中分离出视图数据所有权的操作更容易且更高效。


注意:ViewModel绝不能引用视图、Lifecycle或可能存储对 Activity 上下文的引用的任何类。


实现ViewModel

public class SearchDoctorViewModel extends ViewModel {
    private MutableLiveData<String> mSearchKey;

    public MutableLiveData<String> getSearchKey() {
        if (mSearchKey == null) {
            mSearchKey = new MutableLiveData<>();
        }
        return mSearchKey;
    }

    @Override
    protected void onCleared() {
        super.onCleared();
        mSearchKey = null;
    }
}

ViewModel 的生命周期

ViewModel 对象存在的时间范围是获取 ViewModel 时传递给 ViewModelProvider 的 Lifecycle。ViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 永久消失:对于 Activity,是在 Activity 完成时;而对于 Fragment,是在 Fragment 分离时。

viewmodel-lifecycle

在 Fragment 之间共享数据

假设场景

Activit当前布局,搜索框+fragment

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout 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"
android:background="@color/main_bg_color"
android:fitsSystemWindows="true">

<RelativeLayout
    android:id="@+id/llSearch"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/color_white"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">


        <ImageView
            android:id="@+id/tvLeft"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_centerVertical="true"
            android:paddingHorizontal="@dimen/dimen_16"
            android:src="@mipmap/all_return_nor" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginEnd="@dimen/dimen_8"
            android:scaleType="center"
            android:src="@mipmap/all_search_dis" />

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1">

            <EditText
                android:id="@+id/etSearchDoctor"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@null"
                android:gravity="center_vertical"
                android:hint="@string/string_select_doctor_edit_hint"
                android:paddingVertical="@dimen/dimen_6"
                android:textColor="@color/color_333333"
                android:textColorHint="@color/gray_ababab"
                android:textSize="@dimen/text_size_14" />

            <ImageView
                android:id="@+id/ivClearEdit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_centerVertical="true"
                android:layout_marginEnd="@dimen/dimen_16"
                android:src="@mipmap/all_delete_light" />
        </RelativeLayout>
    </LinearLayout>
</RelativeLayout>

<FrameLayout
    android:id="@+id/frame"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/llSearch"
    android:layout_marginTop="@dimen/dimen_10"
    android:background="@color/color_white" />
</RelativeLayout>

当activity的搜索框有输入事件的时候,fragment根据输入的关键字进行模糊查询,这样就需要实时获取activity的Edittext的输入值

在Activity中

     TextWatcher textWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            String str = s.toString();
            mSearchDoctorViewModel.getSearchKey().setValue(str);
        }
    };
    mEtSearchDoctor.addTextChangedListener(textWatcher);

(```)
在fragment中

  1. 在fragment中获取viewmodel

       SearchDoctorViewModel searchDoctorViewModel =
            new ViewModelProvider(getActivity()).get(SearchDoctorViewModel.class);
    
  2. 监听viewmodel的值

     searchDoctorViewModel.getSearchKey().observe(getActivity(), new Observer<String>() {
        @Override
        public void onChanged(String s) {
            AppLogger.d("searchDoctorViewModel 监听数据改变了  s = " + s);
            if (TextUtils.isEmpty(s)) {
              //根据输入的内容搜索
            } else {
               //无数据输入的判断处理
            }
        }
    });

相关文章

网友评论

      本文标题:ViewModel

      本文链接:https://www.haomeiwen.com/subject/otrvrltx.html