• Android  JetPack~ ViewModel (一)   介绍与使用


     
    ViewModel,MVVM框架中的一部分,他主要作用是处理业务逻辑、数据分配等,他是Mode和VIew连接的桥梁,和MVP相比,他类似P。
    ViewModel类有如下优点:
    1. ViewModel类是具有生命感知的能力,与和他绑定的Activity一样的生命周期,它可以解决请求网络时,Activity被突然销毁造成一些不必要的麻烦。
    2. 设备信息发生变更数据不会丢失(切横竖屏),其实它只有一个生命周期,检测页面销毁时触发
    3. ViewModel 的另一个特点就是同一个 Activity 的 Fragment 之间可以使用ViewModel实现共享数据。
    4. 每个Activity绑定的ViewModel都是独立的(Activity之间)
     

    1、开始使用

    添加依赖

    以前是需要添加依赖的,现在
    方式一: implementation 'androidx.appcompat:appcompat:1.2.0',//这里面也包含ViewModel,LiveData等,
        
    方式二: 也可以单独添加
    implementation "androidx.fragment:fragment:1.1.0"
    implementation "androidx.lifecycle:lifecycle-viewmodel:2.1.0"
    implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"

    2、Activity

    2.1、新建ViewModel

    public class MyViewModel extends ViewModel {
    
        @Override
        protected void onCleared() {
            super.onCleared();
        }
    }
    onCleared方法是ViewModel独有的,当Activity真正退出后,它会调用,而不是销毁后调用,因为旋转屏幕也会调用onDestroy。所以我们可以在这取消网络请求等。平常开发中不做任何操作时,如果有网络请求中,Activity被销毁,那么极有可能请求成功返回结果到activity中造成泄漏等不必要的麻烦。

    解决方式:

    可以使用ViewModel,结合onCleared(),call.cancel()等去做。
    网络请求时,突然销毁activity,那么与之绑定的viewmodel也会销毁,同时我们在onCleared()方法中取消网络连接接口(call.cancel()),就算是有数据返回,activity也不会收到通知,因为数据是从livedata中监听的,只有livedata触发了更新,Activity才会收到通知。
    (当然还有很多其他方式)
     

    2.2、绑定Activity

    这里有如下方式:
    • ViewModelProviders.of(this).get(class)(过时)
    • new ViewModelProvider(this,factory).get(class)(常用)
    • new ViewModelProvider.NewInstanceFactory().create(class);
     

    第一种方式:ViewModelProviders.of(this).get(class)

    ViewModelProviders.of(this).get(MyViewModel.class);
    
    
    implementation "androidx.fragment:fragment:1.1.0"
    implementation "androidx.lifecycle:lifecycle-viewmodel:2.1.0"
    implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
    这种方式是这些依赖中的,当然,如果你的和我的不一样,也无所谓,这不是重点。这个方式比较老了,在源码中也能发现,ViewModelProviders的of方法其实也是调用了ViewModelProvider,自动创建了一个factory。
    ----------------ViewModelProviders.class----------------
    
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
        Application application = checkApplication(checkActivity(fragment));
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(fragment.getViewModelStore(), factory);
    }
     
     

    第二种方式:new ViewModelProvider(this,factory).get(class)

    ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
    传入一个系统的factory。create是创建一个新的实例,而get是先从HashMap中找,找不到就创建新的实例。也是为什么重建的Viewmodel是同一个对象的原因,他会把对象放在ViewModelStore类中HashMap mMap = new HashMap<>();中。这个方式比较新,一般也是这样创建。
     
    public extends ViewModel> T get(@NonNull String key, @NonNull Class modelClass) {
        //第一步:先查找
        ViewModel viewModel = mViewModelStore.get(key);
    
        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        //第二步:没有则创建,并保存在mViewModelStore中
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }

    第三种方式:new ViewModelProvider.NewInstanceFactory().create(class);

    MyViewModel myViewModel1 = new ViewModelProvider.NewInstanceFactory().create(MyViewModel.class);
     
     
    下面写一个LiveData,如果对LiveData不懂的可以翻看之前的博客,目录在顶部
    public class MyViewModel extends ViewModel {
        private MutableLiveData<String> mStr= new MutableLiveData<>();
    
        public MutableLiveData<String> getmStr() {
            return mStr;
        }
        public void setmStr(String s) {
            if(mStr==null){
                mStr = new MutableLiveData<>();
            }
            mStr.setValue(s);
        }
        @Override
        protected void onCleared() {
            super.onCleared();
        }
    }
    全部代码
    public class JPackActivity extends AppCompatActivity {
    
        private ActyJpackLayoutBinding mBinding;
        private MyViewModel myViewModel;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //通过databinding 把activity和view绑定
            mBinding = DataBindingUtil.setContentView(this,R.layout.acty_jpack_layout);
            //通过ViewModeProvider 把activity和ViewModel绑定起来。
            myViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
    
            myViewModel.getmStr().observe(this, new Observer<String>() {
                @Override
                public void onChanged(String s) {
                    mBinding.textShow.setText(s);
                }
            });
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //移除观察者
           
        }
     

    3、Fragment

    使用和Activity中一样。不过需要注意的是传入this和getActivity的区别
    • this:这个ViewModel是独立的,只为这个Fragment单独服务,其他Fragment无法获取到相同内存地址的ViewModel
    • getActivity:使用getActivity()获得的ViewModel 作用域在Activity里和所有他创建碎片的里,意思是你在其他Fragment也获取相同内存地址的ViewModel
     
     @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        MyViewModel myViewModel = new ViewModelProvider(getActivity(), new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
        return inflater.inflate(R.layout.fragment_blank, container, false);
    }
     
    当然还有一个注意点get("key1",MyViewModel.class);,get方法可以传key值,不同的key创建的ViewModel数据是独立的
     

    4、总结

    使用起来非常简单,还要多加练习,才不会被那些xx面试官问步骤咋实现难住。
     
  • 相关阅读:
    KDM & CCA Secure FHE
    【Modbus通讯】记粤西某电厂DCS通讯调试(基础篇)
    pytorch中的hook机制register_forward_hook
    Libevent库的学习
    淘宝API接口,获取商品详情,按关键词搜索,拍立淘,商品评论销量商品类目,买家卖家订单接口等接入演示
    SQL窗口分析函数使用详解系列三之偏移量类窗口函数
    Java 项目 服务器 日志配置
    Leetcode 4.21
    Linux ❀ 进程出现process information unavailable时的消除方法
    Java牛客网社区项目——知识点&面试题
  • 原文地址:https://www.cnblogs.com/cmusketeer/p/17125165.html