Android架构设计模式(三)

原创 2018年04月16日 20:10:04

前言

在Android日常开发中或者在面试过程中总会涉及到“设计模式”这个词。听起来很厉害。实际上在开发中很常见又很难用准确的言语表达出来。随口说出的设计模式有:单例模式,中介者模式,观察者模式等等这些都属于java设计模式,这将会以单独的系列篇在以后的文章中总结。此设计模式系列仅含有应用架构设计模式,这里我就MVC,MVP,MVVM这3个最常见的架构设计模式来总结。

MVVM设计模式

上两篇中总结了MVC、MVP架构,本篇来学习MVVM设计模式,MVVM是Model-View-ViewModel的简写。MVVM主要由以下3个部分组成。

MVVM定义

  1. Model:数据实体模型
  2. View:对应于Activity、xml代表的视图,负责View的绘制以及与用户交互,这里不涉及业务逻辑,不处理数据,UI和数据必须分开
  3. ViewModel:负责完成View与Model间的交互,负责主要的业务逻辑,这里不会持有任何控件的引用,避免造成内存泄露。

MVVM与MVP的区别

MVVM与MVP非常相似,唯一区别就是View和Model进行双向绑定,两者之间有一方发生变化则会反应到另一方面上。而MVP与MVVM的主要区别是,MVP中的View更新需要通过Presenter,而MVVM则不需要,因为View与Model进行了双向绑定,数据的修改会直接反应到View角色上,而View的修改也会导致数据的变更。此时,ViewModel角色需呀做的只是业务逻辑的处理,以及修改View或者Model的状态。MVVM模式优点像ListView与Adapter、数据集的关系,这个Adapter就是ViewModel角色,它与View进行绑定,由于数据集进行绑定,当数据集合发生变化时,调用Adapter的notifyDataSetChanged之后View就直接更新,他们之间没有直接的耦合,使得ListView变得更为灵活。

MVVM的实现实例

Android中常使用databinding来实现MVVM框架。场景:显示一个用户信息的列表到Activity上,在单项中如果用户的年龄小于23,年龄背景就显示为蓝色,否则年龄背景就显示为红色。点击列表中的单项来增加对应用户的年龄。效果图如下。

首先要在build.gradle中添加此段代码,这样我们就可以使用databinding了。

User.java

public class User extends BaseObservable {
    private String name;
    private int age;
    private String sex;
    private int icon;

    public User() {
    }

    public User(String name, int age, String sex, int icon) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.icon = icon;
    }

    @BindingAdapter({"icon"})
    public static void setIcon(ImageView iv, int icon) {
        iv.setBackgroundResource(icon);
    }

    public void onItemClick(View view) {
        setAge(age+1);//点击一次年龄加1
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getIcon() {
        return icon;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

    @Bindable
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        notifyPropertyChanged(BR.age);
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

RootAdapter.java

public class RootAdapter<T> extends BaseAdapter {
    private LayoutInflater inflater;
    private int layoutId;
    private int variableId;
    private List<T> list;

    public RootAdapter(Context context, int layoutId, List<T> list, int resId) {
        this.layoutId = layoutId;
        this.list = list;
        this.variableId = resId;
        inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return list.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewDataBinding dataBinding;
        if (convertView == null) {
            dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false);
        }else{
            dataBinding = DataBindingUtil.getBinding(convertView);
        }
        dataBinding.setVariable(variableId, list.get(position));
        return dataBinding.getRoot();
    }

}

在RootAdapter这个类中就可以看出MVVM的强大之处,这个adapter在没有多余逻辑下基本可以抽成模板来使用,不涉及数据显示相关代码。
MainActivity.java

public class MainActivity extends AppCompatActivity {
    private List<User> users;
    private RootAdapter<User> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ListView lv = findViewById(R.id.lv);
        users = new ArrayList<>();
        adapter = new RootAdapter<>(MainActivity.this, R.layout.item_user, users, BR.user);
        lv.setAdapter(adapter);

        initData();
    }

    private void initData() {
        users.add(new User("王也",22,"男",R.mipmap.wy));
        users.add(new User("冯宝宝",103,"女",R.mipmap.fbb));
        users.add(new User("诸葛青",22,"男",R.mipmap.zgq));
        users.add(new User("张灵玉",24,"男",R.mipmap.zly));
        users.add(new User("夏禾",24,"女",R.mipmap.xh));
        users.add(new User("吕良",17,"男",R.mipmap.ll));
        adapter.notifyDataSetChanged();
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/lv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

item_user.xml

<?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">

    <data>

        <variable
            name="user"
            type="com.fpt.mvvm.User"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:onClick="@{user.onItemClick}"
        android:clickable="true">

        <ImageView
            android:id="@+id/iv"
            android:layout_width="60dp"
            android:layout_height="60dp"
            app:icon="@{user.icon}"
            android:layout_marginLeft="10dp"/>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp">

            <TextView
                android:id="@+id/tv_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.name}"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.sex}"
                android:layout_toRightOf="@+id/tv_name"
                android:layout_marginLeft="10dp"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@{user.age &lt; 23 ? 0xFF0000FF:0xFFFF0000}"
                android:text="@{String.valueOf(user.age)}"
                android:layout_alignParentBottom="true"/>
        </RelativeLayout>

    </LinearLayout>
</layout>

这个item_user.xml中涉及databinding中的重点,有图片显示以及文本显示,点击事件绑定,基本运算和字符串拼接都在此处以及User.java中有体现。具体不在此处细谈。

MVVM总结

MVVM可以算是MVP的升级版,其中的VM是ViewModel的缩写,ViewModel可以理解成是View的数据模型和Presenter的合体,ViewModel和View之间的交互通过Data Binding完成,而Data Binding可以实现双向的交互,这就使得视图和控制层之间的耦合程度进一步降低,关注点分离更为彻底,同时减轻了Activity的压力。


关注我的技术公众号,我会不定期推送关于安卓的文章,内容包含Android日常开发遇到中的问题、常用框架的介绍以及需要熟记的概念等等。
微信扫一扫下方的二维码即可关注:

Android架构设计模式总结(MVX)

Android架构设计模式总结(MVX)一、安卓软件架构设计的目的通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合。这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点,提高程序...
  • anwanfei
  • anwanfei
  • 2017年02月20日 11:42
  • 318

架构,框架和设计模式的区别

架构:简单的说架构就是一个蓝图,是一种设计方案,将客户的不同需求抽象成为抽象组件,并且能够描述这些抽象组件之间的通信和调用。        框架:软件框架是项目软件开发过程中提取特定领域软件的共性部...
  • u014390502
  • u014390502
  • 2016年12月11日 15:42
  • 723

设计模式的三大类别

创建型模式:(5) 抽象工厂、创建者、工厂方法、原型、单例 结构型模式:(7) 适配器、桥接、组合、装饰、外观、享元、代理 行为型模式:(10) 观察者、命令、状态、职责链 解释器、中介者、访...
  • Deaful
  • Deaful
  • 2014年03月05日 21:17
  • 3323

Android常用8种设计模式(三)

常用8种设计模式最后三个:适配器模式、合成模式、访问者模式    -----文章博客园整理而来,尊重原创 对于android开发者来说起,适配器模式简直太熟悉不过,有很多应用可以说是天天在直接或...
  • qq_27489007
  • qq_27489007
  • 2016年12月03日 14:39
  • 764

Android框架设计模式(三)——Observer Method

在介绍观察者模式之前,先补充两个概念:IOC(控制反转)、DIP(依赖倒置)。依赖倒置(控制反转),是框架设计的核心,因为有了它们会产生框架,框架的核心就是把【不变】的留在框架层次,把【变化】的留在应...
  • woshimalingyi
  • woshimalingyi
  • 2016年03月23日 21:03
  • 4597

设计模式的三大分类

1.2 设计模式是什么        俗话说:站在别人的肩膀上,我们会看得更远。设计模式的出现可以让我们站在前人的肩膀上,通过一些成熟的设计方案来指导新项目的开发和设计,以便于我们开发出具有更好的灵...
  • u013233468
  • u013233468
  • 2014年01月13日 00:21
  • 1324

J2EE框架(四)核心设计模式

这一章主要讲两种设计模式:建造者设计模式和工厂设计模式,这两种设计模式在持久层框架基本上都是一起出现,建造者用于加载资源为工厂做好准备,工厂专门用来生产具体对象。这里的资源往往是框架开放给用户自定义的...
  • cd_cd
  • cd_cd
  • 2017年12月21日 16:40
  • 376

八种架构设计模式及其优缺点概述

八种架构设计模式及其优缺点概述, 单库单应用模式:最简单的,可能大家都见过 内容分发模式:目前用的比较多 查询分离模式:对于大并发的查询、业务 微服务模式:适用...
  • mine_song
  • mine_song
  • 2017年04月11日 09:15
  • 2799

设计模式学习之架构设计中的架构模式

设计模式是一套被反复使用、多数人直销的、经过分类编目的、代码设计经验的总结。shiy9og设计模式主要目的是为了额更好的获得可重用性,包括体系结构和实习那代码等的重用,能保证系统体系结构的正确性和代码...
  • lufeng20
  • lufeng20
  • 2012年03月11日 15:40
  • 2903

Android Bluetooth 框架简读 <3>

上一篇从设置开始的,后面的扫描,连接的套路基本上很蓝牙enable差不多,下面从Phone大概介绍. 前面说过HSP,HFP的操作基本上在应用层开始的,另外蓝牙的audio部分也是从这里开始. 所...
  • qq_31726827
  • qq_31726827
  • 2016年04月08日 19:09
  • 548
收藏助手
不良信息举报
您举报文章:Android架构设计模式(三)
举报原因:
原因补充:

(最多只允许输入30个字)