为什么ViewModel能够保存临时数据?

  • 定义
  • 基本使用
  • 实现原理

今天是2022年9月16日 星期五

座位朝向:面向西方写程序,BUG 最少。

今日宜饮:水,果味汽水

女神亲近指数:2.4


定义

ViewModel以绑定生命周期的方式存储和管理界面相关数据,当设备发生屏幕旋转等配置更改后继续保留页面数据。

在ViewModel之前,通常的做法是使用activity的onSaveInastanceState()方法从onCreate()中恢复保存的数据,但是这个方法只适合可以序列化和反序列化的少量数据,并不适合数据较大的数据。 ViewModel除了能够存储和管理界面相关数据外,还能通过对Activity的生命周期监听,在系统销毁后主动释放资源,避免发生内存泄漏。

基本使用

class MainViewModel:ViewModel() {
   val mainLiveData = MutableLiveData() 
}
class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).
        get(MainViewModel::class.java)
        viewModel.mainLiveData.observe(this){
            
        }
    }


通过定义一个MainViewModel类继承自ViewModel抽象类,然后再Activity中初始化MainViewModel。

如果需要在ManViewModel中使用context,MainViewModel需要继承AndroidViewModel。

class MainViewModel(application: Application):AndroidViewModel(application) {
   val mainLiveData = MutableLiveData()

}
 val viewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application)).get(MainViewModel::class.java)
        viewModel.mainLiveData.observe(this){

        }


生命周期

ViewModel为什么能够临时保存界面数据状态?因为ViewModel的作用域包括了整个Activity的生命周期,随着Activity被销毁而清空。


通常该系统首次调用 Activity 对象的 onCreate() 方法是初始化 ViewModel。系统可能会在 activity 的整个生命周期内多次调用 onCreate(),如在旋转设备屏幕时。ViewModel 存在的时间范围是从首次请求 ViewModel 直到 activity 完成并销毁。

实现原理

首先从Activity的父类ComponentActivity开始,实现了ViewModelStoreOwner接口,

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        ContextAware,
        LifecycleOwner,
        ViewModelStoreOwner,
}
public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}
public class ViewModelStore {
    
    private final HashMap mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set keys() {
        return new HashSet<>(mMap.keySet());
    }

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

由于ComponentActivity实现了ViewModelStoreOwner接口,在ComponentActivity中调用getViewModelStore可以获取ViewModel的存储类ViewModelStore,ViewModelStore中使用HashMap存储ViewModel,如果存储的ViewModel的key值相同,则删除oldViewModel旧的ViewModel,替换成最新的ViewModel。

我们来看一下ComponentActivity中是如果保存使用ViewModelStore。

ComponentActivity的构造函数

public ComponentActivity() {
        Lifecycle lifecycle = getLifecycle();
        ......................
        .........................
        //使用lifecycle对activity生命周期进行监听
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                 //如果生命周期为onDestory
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // 清除context
                    mContextAwareHelper.clearAvailableContext();
                    //如果应用配置没有发生改变
                    if (!isChangingConfigurations()) {
                        //清除ViewModelStore中HashMap存储的ViewModel
                        getViewModelStore().clear();
                    }
                }
            }
        });
     getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                //初始化ViewModelStore
                ensureViewModelStore();
                getLifecycle().removeObserver(this);
            }
        });

当ComponentActivity退出销毁时,会调用getViewModelStore().clear(),清除ViewModelStore中HashMap存储的ViewModel,释放资源。我们接着看数据是如何保存的?

void ensureViewModelStore() {
        //如果存储类为null
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // 从 NonConfigurationInstances 恢复 ViewModelStore
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
    }
  static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }

NonConfigurationInstances是一个静态类,它有两个成员变量Object 和ViewModelStore ;如果ViewModelstore如果不存在,则将NonConfigurationInstances的成员变量保存的ViewModelstore赋值给ViewModelStore 。我们接着看一下getLastNonConfigurationInstance。

    //获取上一次保存的数据
    @Nullable
    public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }

mLastNonConfigurationInstances 是上一次保存的数据实例,当Activity被创建的时候,调用attach方法,mLastNonConfigurationInstances = lastNonConfigurationInstances;当应用配置发生改变时,如屏幕旋转,会导致Activity重建,这个时候会获取上一次保存的mLastNonConfigurationInstances ,并取出其中存储的viewmodestore,最后得到ViewModel,直接从ViewModel中得到数据恢复界面列表。

当activity退出销毁时,通过lifecycle对activity的生命周期监听,如果配置没有发生改变,正常退出,则直接情况ViewModelStore。如果还有对Lifecycle不理解的痛苦可以参考Jetpack之Lifecycle怎么绑定Activity生命周期?

 //使用lifecycle对activity生命周期进行监听
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                 //如果生命周期为onDestory
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // 清除context
                    mContextAwareHelper.clearAvailableContext();
                    //如果应用配置没有发生改变
                    if (!isChangingConfigurations()) {
                        //清除ViewModelStore中HashMap存储的ViewModel
                        getViewModelStore().clear();
                    }
                }
            }
        });

今天的分享就到这里了,相信大家都ViewModel有一定的了解了,关注小编,学习不迷路,欢迎大家一起学习!

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章