• 移动架构-MVVM框架


    MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开

    MVVM的优点

    可重用性:你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。 在Android中,布局里可以进行一个视图逻辑,并且Model发生变化,View也随着发生变化
    低耦合:以前Activity、Fragment中需要把数据填充到View,还要进行一些视图逻辑。现在这些都可在布局中完成,甚至都不需要再Activity、Fragment去findViewById。这时候Activity、Fragment只需要做好的逻辑处理就可以了

    MVVM

    角色

    View: 对应于Activity和XML,负责View的绘制以及与用户交互
    Model: 实体模型
    ViewModel: 负责完成View与Model间的交互,负责业务逻辑

    数据驱动

    在常规的开发模式中,数据变化需要更新UI的时候,需要先获取UI控件的引用,然后再更新UI。获取用户的输入和操作也需要通过UI控件的引用。在MVVM中,这些都是通过数据驱动来自动完成的,数据变化后会自动更新UI,UI的改变也能自动反馈到数据层,数据成为主导因素。这样MVVM层在业务逻辑处理中只要关心数据,不需要直接和UI打交道,在业务处理过程中简单方便很多

    MVVM是一种架构模式,而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个工具

    DataBinding支持的表达式

    • 数学表达式:+ - / * %
    • 字符串拼接:+
    • 逻辑表达式:&& ||
    • 位操作符:& | ^
    • 一元操作符:+ - ! ~
    • 位移操作符:>> >>> <<
    • 比较操作符:== > < >= <=
    • instanceof
    • 分组操作符:()
    • 字面量:character, String, numeric, null
    • 强转、方法调用
    • 数组访问:[]
    • 三元操作符:?:
      android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
      支持dimen,还支持colorstringdrawableanim
    • 聚合判断(Null Coalescing Operator)语法??
      android:text="@{user.userName ?? user.realName}"
      意思是如果userName为null,则显示realName
    • 字符拼接
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="@{`username is :`+user.username}"/>
    

    这里的字符拼接不是用单引号哦,用的是ESC按键下面那个按键按出来的。目前DataBinding中的字符拼接还不支持中文
    官方手册:https://developer.android.com/tools/data-binding/guide.html

    MVVM用法

    模板写法

    <layout xmlns:android="http://schemas.android.com/apk/res/android"    >   
    	<data>    
    		<!--此处定义该布局要用到的数据的名称及类型-->
    	</data>
    	<!--此处按照常规方式定义要使用的布局,其中可以使用binding表达式代表属性值,所谓binding表达式,指形如"@{user.firstName}"的表达式-->
    </layout>
    

    自定义Binding类名(Custom Binding Class Names)

    • 以为根节点布局,android studio默认会自动产生一个Binding类。类名为根据布局名产生,如一个名为activity_simple的布局,它的Binding类为ActivitySimpleBinding,所在包为app_package/databinding
    • 也可以自定义Binding类的名称和包名
    <data class="CustomBinding"></data> 在app_package/databinding下生成CustomBinding
    <data class=".CustomBinding"></data> 在app_package下生成CustomBinding
    <data class="com.example.CustomBinding"></data> 明确指定包名和类名
    

    Layout布局中Includes 标签使用

    <include layout="@layout/name"
    	bind:user="@{user}"/>
    

    BaseObservable的方式

    使User继承BaseObservable,在get方法上加上注解@Bindable,会在BR(BR类自动生成的)生成该字段标识(int)
    set方法里notifyPropertyChanged(BR.field);

    @Bindable
    public String getUserName() {
        return userName;
    }
    

    理解实例

    在项目gradle的android标签下中添加

    dataBinding{
        enabled true
    }
    

    编写测试类

    public class User {
        private String name;
        private String password;
    
        public User(String name, String password) {
            this.name = name;
            this.password = password;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    

    编写布局

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <data>
            <!--第一种引入方式-->
            <variable
                name="user"
                type="com.cj5785.mvvmdesign.User" />
            <!--第二种引入方式-->
            <!--<import type="com.cj5785.mvvmdesign.User" />-->
            <!--<variable-->
            <!--name="user"-->
            <!--type="User" />-->
            <!--如果有多个相同model,可以取别名-->
            <!--<import alias="typeUser" type="com.cj5785.mvvmdesign.User" />-->
            <!--<variable name="user" type="typeUser" />-->
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:text="@{user.name}" /><!--显示字段-->
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:text="@{user.password}" /><!--显示字段-->
        </LinearLayout>
    </layout>
    

    在Activity中调用测试

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    //        使用MVVM时候,这里不能使用setContentView
    //        setContentView(R.layout.activity_main);
    		//ActivityMainBinding在编译时自动生成
            ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            User user = new User("jack","123456");
            binding.setUser(user);
        }
    }
    

    这样就完成了MVVM模型最简单的运用
    此时就显示出了设置的name和password
    接下来测试数据变化更新UI
    修改测试类

    public class User extends BaseObservable{
        private String name;
        private String password;
    
        public User(String name, String password) {
            this.name = name;
            this.password = password;
        }
    
        @Bindable
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
            notifyPropertyChanged(BR.name);
        }
    
        @Bindable
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
            notifyPropertyChanged(BR.password);
        }
    }
    

    在Activity中使用延迟设置

    public class MainActivity extends AppCompatActivity {
    
        User user;
        Handler handler = new Handler();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    //        使用MVVM时候,这里不能使用setContentView
    //        setContentView(R.layout.activity_main);
            ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            user = new User("jack", "123456");
            binding.setUser(user);
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    user.setName("Bob");
                    user.setPassword("654321");
                }
            }, 5000);
        }
    }
    

    然后可以看到在经历5秒以后,文字被改变了
    使用MVVM框架加载网络图片又怎么做呢
    首先导入com.squareup.picasso:picasso依赖
    在User中添加相应的图片获取方法

    public class User extends BaseObservable{
        private String name;
        private String password;
        private String header;
    
        public User(String name, String password,String header) {
            this.name = name;
            this.password = password;
            this.header = header;
        }
    
        @BindingAdapter("bind:header")
        public static void getImage(ImageView imageView,String url){
            Picasso.with(imageView.getContext()).load(url).into(imageView);
        }
    
        @Bindable
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
            notifyPropertyChanged(BR.name);
        }
    
        @Bindable
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
            notifyPropertyChanged(BR.password);
        }
    
        public String getHeader() {
            return header;
        }
    
        public void setHeader(String header) {
            this.header = header;
        }
    }
    

    修改布局文件

    <?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.cj5785.mvvmdesign.User" />
            <!--第二种引入方式-->
            <!--<import type="com.cj5785.mvvmdesign.User" />-->
            <!--<variable-->
            <!--name="user"-->
            <!--type="User" />-->
            <!--如果有多个相同model,可以取别名-->
            <!--<import alias="typeUser" type="com.cj5785.mvvmdesign.User" />-->
            <!--<variable name="user" type="typeUser" />-->
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:header="@{user.header}"/>
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:text="@{user.name}" /><!--显示字段-->
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:text="@{user.password}" /><!--显示字段-->
        </LinearLayout>
    </layout>
    

    在Activity中直接调用

    public class MainActivity extends AppCompatActivity {
    
        User user;
        Handler handler = new Handler();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    //        使用MVVM时候,这里不能使用setContentView
    //        setContentView(R.layout.activity_main);
            ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            user = new User("jack", "123456","http://i0.hdslb.com/bfs/archive/42172b20c899bcbbad0d46868af81b8081e999f1.jpg");
            binding.setUser(user);
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    user.setName("Bob");
                    user.setPassword("654321");
                }
            }, 5000);
        }
    }
    

    接下来看看除了使用BaseObservable的另一种方式

    public class UserField {
        public ObservableField<String> name = new ObservableField<>();
        public ObservableField<String> password = new ObservableField<>();
    }
    

    布局

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <data>
            <variable
                name="field"
                type="com.cj5785.mvvmdesign.UserField"/>
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:text="@{field.name}" /><!--显示字段-->
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18sp"
                android:text="@{field.password}" /><!--显示字段-->
        </LinearLayout>
    </layout>
    

    调用

    public class FieldTestActivity extends Activity {
        UserField userField = new UserField();
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            binding.setField(userField);
            userField.name.set("Alen");
            userField.password.set("121212");
        }
    }
    
  • 相关阅读:
    几种简单排序算法
    【转】虚拟机下CentOS7开启SSH连接
    【转】SignalR来做实时Web聊天
    加密算法(DES,AES,RSA,MD5,SHA1,Base64)比较和项目应用
    C#加密解密(DES,AES,Base64,md5,SHA256,RSA,RC4)
    【C#公共帮助类】给大家分享一些加密算法 (DES、HashCode、RSA、AES等)
    对称加密与非对称加密
    PowerDesigner概念模型与物理模型相互转换及导出数据字典
    SQO2008配置管理工具服务显示远程过程调用失败
    MongoDB学习笔记-数据格式及数据类型
  • 原文地址:https://www.cnblogs.com/cj5785/p/10664605.html
Copyright © 2020-2023  润新知