Jetpack mvvm 终

作者: 三月四晴 | 来源:发表于2020-10-15 16:06 被阅读0次
    • 前面3篇讲完了mvvm必要的3个库ViewModel LiveData DataBinding
    • 本篇将讲解如果用这3者结合组成mvvm的架构
    • 在此之前让我们先了解下mvc mvp 最后再来说下mvvm
    MVC
    image.png
    • 其实Android本身就有mvc的例子了
    • 比如直接新建一个Activity 在xml布局定义一个按钮实现点击事件 当用户点击按钮的时候我们在按钮的OnClickListener接口回掉中做一个1+1的运算Toast弹出1+1的结果 这一个简单的步骤就包含了mvc的结构了
    • M指Model(模型层)在上述的例子指1+1的运算结果
    • V指View是视图 用户看到的页面
    • C指Controller控制器在上述例子对应点击时间
    • 当View视图被用户点击,然后Controller监听到了这个操作进行Mode操作得到2的值反馈给View,然后用户看到了View所弹出Toast消息
    • 这个例子很好的对应了上图Model、View、Controller的关系
      优点:
      1、业务逻辑全部分离到Controller中,模块化程度高。
      2、观察者模式可以做到多视图同时更新。
      缺点:
      1、Model和View之间是直接进行交互,就必然会导致Model和View之间的耦合。
      2、所有逻辑都写在Controller层,导致Controller层特别臃肿。
    • 优缺点这个百度一大堆我就直接抄了😂
    • 适用场景:适用于功能较少、业务逻辑简单、界面不复杂的小型项目。
    MVP
    • mvp这个呢很多大型的商业app啥的大都用的这个结构,可以说在android算是主流的架构模式
    • M 还是那个Model
    • V 还是那个视图View
    • P 就是Presenter(主持人) 在下面的关系图中P持有M和V做M、V之间的交互桥梁
    image.png
    • 对比mvc可以发现由于Presenter的存在直接处理了V、M直接的耦合,所以比mvc 降低了耦合。
    • 具体实现就不扯了网上可以搜罗一大堆
    • 下面放个我之前写的Demomvp-retrofit2-rxjava2

    优点:
    1、模型与视图完全分离,我们可以修改视图而不影响模型。
    2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部。
    3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。
    4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。
    缺点:Presenter作为桥梁协调View和Model,就会导致Presenter变得很臃肿,维护比较困难。

    • 哈哈哈,这个优缺点我也是抄的
    MVVM
    • 这才是本文肉戏


      image.png
    • M不在是前面的Model了,MVVM的Model主要是封装数据存储或操作的一些逻辑(工具类),还会提供一系列的实体类用于UI绑定。

    • V View指做处理界面数据的展示,不做数据处理、业务逻辑等操作。

    • VM ViewModel做数据的获取业务逻辑操作然后通过数据绑定(DatabBinding)和xml进行绑定

    优点:
    • 低耦合,数据和业务逻辑处于一个独立的ViewModel中,ViewModel只需要关注数据和业务逻辑,不需要和View层打交道。
    • 可重用性,你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
    • 可分开独立开发,MVVM的分工是非常明显的,由于View和ViewModel之间是松散耦合的:一个是处理业务和数据、一个是专门的UI处理。所以,完全可以由两个人分工来做,一个做UI(XML和Activity)一个写ViewModel,效率更高。
    • 由于各层分工明确,极便于单元测试;
    • 相对于MVP而言,MVVM不需要我们手动的处理大量的View和Model相关操作,也非常完美的解耦了View层和ViewModel。
    缺点:
    • 数据绑定使得 Bug 很难被调试,你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。

    • 对于过大的项目,数据绑定需要花费更多的内存,而对与过于简单的界面,使用MVVM无异是杀鸡用牛刀。


    • 正式开始敲代码

    • 网络的部分我用的retrofit2+Rxjava组合,用了wanandroid的公开的接口。

    public class MvvMViewmodel extends ViewModel {
        public MutableLiveData<Integer> mutableLiveData = new MutableLiveData<>();
        public MutableLiveData<State> state = new MutableLiveData<>();
        public LiveData<List<WanAndroidNewsBean.ItemDetailsBean>> listLiveData;
        private  int page =0;
        public  List<WanAndroidNewsBean.ItemDetailsBean> list = new ArrayList<>();
        public CompositeDisposable dis;
    
    
        public MvvMViewmodel() {
            dis = new CompositeDisposable();
            listLiveData = Transformations.switchMap(mutableLiveData, new Function<Integer, LiveData<List<WanAndroidNewsBean.ItemDetailsBean>>>() {
                @Override
                public LiveData<List<WanAndroidNewsBean.ItemDetailsBean>> apply(Integer input) {
                    return getData(input);
                }
            });
    
        }
        public void getPageUpData(){
           mutableLiveData.setValue(page>0?page-1:page);
        }
        public void getPageNextData(){
            mutableLiveData.setValue(page+1);
        }
    
        private LiveData<List<WanAndroidNewsBean.ItemDetailsBean>> getData(int page){
            MediatorLiveData<List<WanAndroidNewsBean.ItemDetailsBean>> mediatorLiveData = new MediatorLiveData<>();
            HttpData.getRetrofit().create(PathApiService.class).getNes(page)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer<WanAndroidNewsBean>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            state.setValue(new State(StateType.LOADING,""));
                            dis.add(d);
                        }
    
                        @Override
                        public void onNext(WanAndroidNewsBean wanAndroidNewsBean) {
                            state.setValue(new State(StateType.SUCCESS,""));
                            mediatorLiveData.setValue(wanAndroidNewsBean.getData().getDatas());
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            state.setValue(new State(StateType.ERROR,e.getMessage()));
                        }
    
                        @Override
                        public void onComplete() {
                            Log.e("TAGSS","onComplete");
                        }
                    });
            return mediatorLiveData;
        }
    
        @Override
        protected void onCleared() {
            super.onCleared();
            if(dis!=null){
                dis.dispose();
            }
        }
    }
    
    public class MvvmMainActivity extends BaseActivity {
        private MvvMViewmodel viewmodel;
        private ActivityMvvmMainBinding activityMvvmMainBinding;
        private RecycleAdapter recycleAdapter;
        private Dialog diglog;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
    
        @Override
        public void init() {
            diglog = MyDiglog.createLoadingDialog(this,"请求中");
            activityMvvmMainBinding= getViewDataBinding();
            viewmodel = new ViewModelProvider(this).get(MvvMViewmodel.class);
            diglog.show();
            activityMvvmMainBinding.setLifecycleOwner(this);
            viewmodel.getPageUpData();
            activityMvvmMainBinding.setViewModel(viewmodel);
            activityMvvmMainBinding.recycle.setLayoutManager(new LinearLayoutManager(this));
            recycleAdapter = new RecycleAdapter(viewmodel.list);
    
            activityMvvmMainBinding.recycle.setAdapter(recycleAdapter);
            viewmodel.listLiveData.observe(this, new Observer<List<WanAndroidNewsBean.ItemDetailsBean>>() {
                @Override
                public void onChanged(List<WanAndroidNewsBean.ItemDetailsBean> itemDetailsBeans) {
                 viewmodel.list.clear();
                 viewmodel.list.addAll(itemDetailsBeans);
                 recycleAdapter.notifyDataSetChanged();
                }
            });
    
            viewmodel.state.observe(this, new Observer<State>() {
                @Override
                public void onChanged(State state) {
                    diglog.dismiss();
                    switch (state.getCode()){
                        case ERROR:
                            Toast.makeText(MvvmMainActivity.this,state.getMsg(),Toast.LENGTH_LONG).show();
                            break;
                        case LOADING:
                            diglog.show();
                            break;
    
                    }
                }
            });
        }
    
        @Override
        public int getLayout() {
            return R.layout.activity_mvvm_main;
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(diglog!=null){
                diglog.dismiss();
            }
            diglog= null;
        }
    
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <layout>
        <data>
            <variable
                name="viewModel"
                type="com.sanyue.jetpakcdemonew.mvvm.MvvMViewmodel" />
    
        </data>
    <androidx.constraintlayout.widget.ConstraintLayout 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"
        tools:context=".mvvm.MvvmMainActivity">
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycle"
            android:layout_width="match_parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/page_up"
            android:layout_height="0dp"/>
        <Button
            android:id="@+id/page_up"
            android:layout_width="wrap_content"
            android:text="上一页"
            android:onClick="@{()->viewModel.getPageUpData()}"
            android:enabled="@{viewModel.mutableLiveData>0?true:false}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@id/pageIndex"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_height="wrap_content"/>
        <TextView
            android:id="@+id/pageIndex"
            android:layout_width="wrap_content"
            android:textColor="@android:color/holo_red_dark"
            android:textSize="18sp"
            app:layout_constraintLeft_toRightOf="@+id/page_up"
            app:layout_constraintRight_toLeftOf="@+id/page_down"
            app:layout_constraintTop_toTopOf="@+id/page_down"
            app:layout_constraintBottom_toBottomOf="@+id/page_down"
            android:text="@{String.valueOf(viewModel.mutableLiveData)}"
            android:layout_height="50dp"/>
        <Button
            android:id="@+id/page_down"
            android:layout_width="wrap_content"
            android:text="下一页"
            android:onClick="@{()->viewModel.getPageNextData()}"
            app:layout_constraintLeft_toRightOf="@id/pageIndex"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_height="wrap_content"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
    
    效果图
    • 从代码上可以把我的MvvMViewmodel类中的变量mutableLiveData
      、listLiveData、list看作是Moldel部分,通过ViewModel部分用LiveData跟DataBinding对View部分(activity和xml)进行了绑定,当用户点击下一页就回去执行getPageNextData方法,当listLiveData获取到数据就去更新适配器的数据。
    • 大概就这么多了
    • 代码都在jetpackDemo欢迎Star
    • 可以说的是认真看完这个系列的文章,在自己根据文章的源码解读部分看下源码,相信你在看网上的MVVM列子什么的就不会让你一看懵逼二看还是懵逼了


    相关文章

      网友评论

        本文标题:Jetpack mvvm 终

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