Android架构组件-ViewModel

前言

在使用一个新的组件之前,我们需要了解为什么需要使用它、如何使用、使用过程中的注意事项、可扩展或可提升的地方。当我们深入透彻理解这些后,开发中遇到任何问题都可以迎刃而解。当然需要了解这些内容,我们必须熟悉源码的实现过程,这样才能做到心中有数。

为什么需要使用

概念

ViewModel主要是为了保存和管理UI相关的数据,能够在我们的配置发生变化的时候保存数据,比如在屏幕旋转时,可以直接使用上次保存的ViewModel对象以及其中的数据。

我们知道,当屏幕旋转,默认情况一下原有的Activity会销毁,从而重新创建新的Activity,此时,UI控制器存储的相关数据会丢失,重新执行onCreate()等生命周期方法,从而重新加载我们需要的数据。从UI体验来讲,又需要再次等待一个加载数据(网络或者本地数据库)的过程;从技术的角度来讲,消耗不必要的系统资源做以前已经完成过的事。如果我们想保存数据,有一种简单的方法,就是使用使用onSaveInstanceState(),但是它只能存储少量的可序列化的数据,不适合大量的数据或者类似bitmap之类的。如果使用ViewModel则就能解决上面的问题。

使用ViewMode的优点:
  1. 当我们UI控制器的配置发生变化时,可以使用之前保存的数据,从而减少不必要的系统资源消耗,提升了体验和性能。
  2. 解耦和单一职责,将Activity或者Fragment相关的UI数据交给ViewModel处理,避免UI控制器的臃肿
  3. 可以实现同一个Activity中不用Fragment之间的通信。
ViewMode作用范围:

在这里插入图片描述

如何使用

1.创建ViewModel
public class MeViewModel extends ViewModel {
    private MutableLiveData<UserEntity> userInfo;
    
    //一般我们在UI的onCreate()中异步加载数据,因此需要按照以下方式操作,才能保证再次onCrate()不会重复异步加载数据。
    public LiveData<UserEntity> getUser(){
        if(userInfo == null){
            userInfo = new MutableLiveData<>();
            loadUser();
        }
        return userInfo;
    }

    private void loadUser(){
        //from net or db
        //userInfo.postValue(userEntity);
    }
    
    //可在Activity或者Fragment onDestroy()之前做一些操作
    @Override
    protected void onCleared() {
        super.onCleared();
    }
}
2.创建需要使用Application的ViewModel
public class TestViewModel extends AndroidViewModel {
    public TestViewModel(@NonNull Application application) {
        super(application);
    }

    public void loadData(){
        //可以使用全局的Application
        Application application = getApplication();
        //do other
    }
}
3.UI控制器中使用
public class MeActivity extends AppCompatActivity {

    private MeViewModel viewModel;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = ViewModelProviders.of(this).get(MeViewModel.class);
        viewModel.getUser().observe(this, new Observer<UserEntity>() {
            @Override
            public void onChanged(@Nullable UserEntity userEntity) {
                //update UI
            }
        });

    }
}

使用中的注意事项

ViewModel中不能持有Activity、Fragment、View的引用,因为ViewModel的生命周期比当前绑定的Activity或者Fragment更长,会导致内存泄漏。

使用中的疑惑

疑惑一:如何在配置发生变化时恢复当前的ViewModel以及为什么能够存储大量的数据

ViewModel对象的恢复是在这个地方执行的,但是最终的实现原理还没有研究

  protected void onCreate(@Nullable Bundle savedInstanceState) {
        this.mFragments.attachHost((Fragment)null);
        super.onCreate(savedInstanceState);
        FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
        if (nc != null && nc.viewModelStore != null && this.mViewModelStore == null) {
            this.mViewModelStore = nc.viewModelStore;
        }
        ......
    }

存储大量的数据和onSaveInstance()存储少量可序列化原理还未研究

疑惑一:Activity重新onCreate()之后,如何能将原有保存的数据刷新到UI上的

我们在Activity中使用ViewModel是按照下面的方式使用的,那么保存的数据是如何刷新的UI的?

public class MeActivity extends AppCompatActivity {

    private MeViewModel viewModel;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = ViewModelProviders.of(this).get(MeViewModel.class);
        viewModel.getUser().observe(this, new Observer<UserEntity>() {
            @Override
            public void onChanged(@Nullable UserEntity userEntity) {
                //update UI
            }
        });

    }
}

这里其中的妙处在LiveData,onCreate()重新执行,执行observe方法,添加新的LifecycleBoundObserver,而默认LifecycleBoundObserver的mLastVersion为START_VERSION,而此时原有的LiveData的mVersion版本号大于START_VERSION版本号,因此会回调onChanged()方法。

public abstract class LiveData<T> {
    .....
    static final int START_VERSION = -1;
    private int mVersion = START_VERSION;

    //改变mVersion值
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
    
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //添加LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }
    
    class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver{
        .......
    }
    
     private abstract class ObserverWrapper {
        final Observer<T> mObserver;
        boolean mActive;
        //默认值
        int mLastVersion = START_VERSION;
        .....
    }
    
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        //回调onChanged()方法
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }
    

    .....

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值