美文网首页
(1)MVVM初见

(1)MVVM初见

作者: 雨落川川 | 来源:发表于2020-10-28 16:02 被阅读0次

    MVVM架构模式已经非常火了,我还是只知其一不知其二,搜了很多帖子学习,这里整理一下学习笔记。

    a.便于理解,先把一些字面意思放在这里:
    Model 模型(数据层)

    是应用程序中处理程序数据逻辑的部分,通常负责从本地数据库存取,远程存取数据。

    View 视图(UI显示)

    是应用程序中处理数据显示的部分,通常视图都是依据模型来创建的。

    Controller 控制者,管理者,调度员

    在应用程序中处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

    Presenter 主持人
    ViewModel 视图模型
    Repository 仓库,存放处
    1.MVC

    MVC的模式优点在于分离UI与业务职责,增加可测试性与可扩展性,但缺点是,View即依赖于Controller又依赖于Model,在修改UI内容时,也需要修改对应的Model,降低架构的灵活性,View和Model的职责存在部分重叠,耦合度高,实际操作中很难按照MVC模式严格去分离。

    2.MVP

    Model-View-Presenter ;MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
    MVP模式的优点是模型与视图完全分离,我们可以修改视图而不影响模型,因为在这个模式下,所有的交互都发生在Presenter内部,也利于脱离用户接口来测试业务逻辑。缺点是会导致视图和Presenter的交互过于频分,Presenter与具体的View没有直接关联,而是通过定义好的接口进行交互,这会导致有大量的接口生成,造成代码繁具,很难维护,这也是很多像我一样从入坑到放弃这种模式的原因。

    3.MVVM

    MVP的特质是“依赖倒置”,MVVM的特质是“数据驱动”。
    学这个的目的,是因为这句话,显然说明二者并没有谁演化自谁的关系了,JetPack MVVM是MVVM模式在Android开发中的具体落实,“数据驱动”这个理解有点难,看帖子不理解就找个教程写个Demo理解一下,B站是个学习网站,很多优质UP主提供了帮助,这里贴一下一个小Demo:


    篮球比赛计分器

    一个计分器,点击加分向对应的队加相应的分数,点击回退取消上一步的操作,点击重置将两队的比分清零。
    首先定义MyViewModel,继承自ViewModel,在这里我们定义数据,并处理逻辑。

    public class MyViewModel extends ViewModel {
        // 定义两队的分数
        // MutableLiveData可修改的LiveData,因为分数需要变化,LiveData
        private MutableLiveData<Integer> aTeamScore;
        private MutableLiveData<Integer> bTeamScore;
        //缓存两队当前分数,用于回退一步
        private int aBack, bBack;
    
        public MutableLiveData<Integer> getATeamScore() {
            if (aTeamScore == null) {
                aTeamScore = new MutableLiveData<>();
                aTeamScore.setValue(0);
            }
            return aTeamScore;
        }
    
        public MutableLiveData<Integer> getBTeamScore() {
            if (bTeamScore == null) {
                bTeamScore = new MutableLiveData<>();
                bTeamScore.setValue(0);
            }
            return bTeamScore;
        }
    
        /**
         * 给A队加分,在添加之前保留A、B两队的分数,用于在执行undo操作时使用
         * @param p 要加的分数
         */
        public void aTeamAdd(int p) {
            aBack = aTeamScore.getValue();
            bBack = bTeamScore.getValue();
            aTeamScore.setValue(aTeamScore.getValue() + p);
        }
    
        public void bTeamAdd(int p) {
            aBack = aTeamScore.getValue();
            bBack = bTeamScore.getValue();
            bTeamScore.setValue(bTeamScore.getValue() + p);
        }
    
        /**
         * 清零
         */
        public void reset() {
            aBack = aTeamScore.getValue();
            bBack = bTeamScore.getValue();
            aTeamScore.setValue(0);
            bTeamScore.setValue(0);
        }
    
        public void undo() {
            aTeamScore.setValue(aBack);
            bTeamScore.setValue(bBack);
        }
    }
    

    布局文件的内容除了常规控件的内容,也就是使用了JetPack提供的DataBinding,篇幅有限这里仅仅对新生事物粘贴一下:

    <?xml version="1.0" encoding="utf-8"?>
    <layout 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">
    
        <data>
    
            <variable
                name="data"
                type="com.nxhope.community.state.MyViewModel" />
        </data>
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".ui.BasketballScoring">
    
          <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginBottom="8dp"
                android:text="@{String.valueOf(data.getATeamScore())}"
                android:textColor="#E91E63"
                android:textSize="80sp"
                app:layout_constraintBottom_toTopOf="@+id/guideline10"
                app:layout_constraintEnd_toStartOf="@+id/guideline7"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="@+id/guideline9"
                tools:text="120" />
    
         <Button
                style="@style/button_one"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginBottom="8dp"
                android:onClick="@{()->data.aTeamAdd(1)}"
                android:text="+1"
                app:layout_constraintBottom_toTopOf="@+id/guideline11"
                app:layout_constraintEnd_toStartOf="@+id/guideline7"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="@+id/guideline10" />
    
        <ImageButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="60dp"
                android:layout_marginTop="8dp"
                android:layout_marginEnd="8dp"
                android:layout_marginBottom="8dp"
                android:onClick="@{()->data.undo()}"
                app:layout_constraintBottom_toTopOf="@+id/guideline14"
                app:layout_constraintEnd_toStartOf="@+id/guideline7"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="@+id/guideline13"
                app:srcCompat="@drawable/ic_baseline_undo_24" />
    
       </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
    
    

    布局文件转换为data-bingding layout这步可以不用手写,windows用户选中布局的根节点alt+enter就会提示出一个选项“convert to data binding layout" 的内容, 转换后会多出来<data>节点中的内容,我们只需要name中命名,在type中导入我们定义好的ViewModel即可。

    剩下的事情就是为控件绑定ViewModel提供的数据或者操作了,TextView中
    android:text="@{String.valueOf(data.getATeamScore())}"为A队分数显示区域绑定数据,Button中
    android:onClick="@{()->data.aTeamAdd(1)}"绑定了为A队加1的操作,当然加2加3就类似了,ImageButton绑定了我们在ViewModel中定义的undo()操作,也就是回退一步。可以看到,到目前为止,我们好像只关心了布局文件和ViewModel的内容,对于页面Activity反而还没下手,不像常规操作,之所以这样,是因为Activiy中真的没啥可处理了,看代码:

    public class BasketballScoring extends AppCompatActivity {
        private MyViewModel viewModel;
        private ActivityBasketballScoringBinding binding;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //DataBinding
            binding = DataBindingUtil.setContentView(this, R.layout.activity_basketball_scoring);
            //ViewModel
            viewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
            binding.setData(viewModel);
            binding.setLifecycleOwner(this);
        }
    }
    

    Activity中我们只是做了将布局和ViewModel绑定,当然这里还写了一些LiveData和Lifecycle的内容(我还没研究透彻,这里按下不表,听下回分说),不是重点,重点是,Activity中太简洁了,常见的FindViewById( ),setOnclickListener( ),setText( )统统不见踪影,以及我们可能要定义的常量,Bean什么的也没了,这就很香了。
    玩玩这个Demo,比如删除布局文件中的一些内容,常规方式可能就会出现空指针,控件找不到造成的Crash,但现在不会了,MVVM模式用于解决“视图调用一致性问题”这句话也诚不欺我,这时候再拿出KunMinX大佬的图:



    再品品,想总结些内容,品出来的是:“我是小白,特别的白”、
    帖子前面提到了Repository ,这里面并没有说,本着的是不懂就不装懂的原则,况且程序员有的东西懂了怎么用,不一定会表达,继续学习,Android推出的JetPack内容是时候学学了:


    Jetpack

    相关文章

      网友评论

          本文标题:(1)MVVM初见

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