android MVVM框架学习总结(一)

android MVVM框架学习总结

1.简单的数据绑定示例

(1)布局文件这样写

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

在标签中 描述了一个变量user,它对应的类型为”com.example.User”
布局中使用“@ { }”语法来书写表达式。如为TextView的文本设置成user. firstName.
(2) 数据对象这样写

public class User {
   public final String firstName;
   public final String lastName;
   public User(String firstName, String lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }
}

在数据绑定中,访问@{user.firstName},那么默认就会访问同名的属性firstName,或对应的getFirstName方法。

(3)数据绑定
默认情况下,绑定类将基于布局文件的名称来产生
如布局文件为main_activity.xml,这样生成的类是 MainActivityBinding
如下设置Activity的contentView:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
   User user = new User("Test", "User");
   binding.setUser(user);
}

上文说,在xml中用表达式可以获取数据,那么同样的,在代码中也可以设置数据,如这里的:binding.setUser(user);
还可以使用inflate的方式来获取生成数据绑定类:

MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater());

如果是在一个adapter中来使用,那么可以如下:

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

2.事件处理

可以在xml中编写表达式处理事件。比如 View.OnLongClickListener有一个方法为onLongClick(),那么它对应的事件就是android:onLongClick。当绑定事件后,会自动将该listener绑定在View上。处理事件有两种方法,
1. 方法引用:可以引用符合listener 任意方法签名规则的方法。
2. 监听器绑定:使用lambda表达式。

1.方法引用
比如定义一个符合OnClickListener#onClick(View view)方法参数签名规则的方法:

public class MyHandlers {
    public void onClickFriend(View view) { ... }
}

如下在xml中绑定并使用:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="handlers" type="com.example.Handlers"/>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
           android:onClick="@{handlers::onClickFriend}"/>
   </LinearLayout>
</layout>

2.监听器绑定
表达式使用的方法就可以定义的比较随意了,不用像”方法引用”那样遵循特定规则,如一个方法

public class Presenter {
    public void onSaveClick(Task task){}
}

xml中使用它

<?xml version="1.0" encoding="utf-8"?>
  <layout xmlns:android="http://schemas.android.com/apk/res/android">
      <data>
          <variable name="task" type="com.android.example.Task" />
          <variable name="presenter" type="com.android.example.Presenter" />
      </data>
      <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
          <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
          android:onClick="@{() -> presenter.onSaveClick(task)}" />
      </LinearLayout>
  </layout>

像上面,我们并没有定义onClick(android.view.View) 参数view。监听器绑定,允许我们忽略所有的参数。如果想要使用参数,可以忽略参数类型,随意定义一个名字。监听器绑定还有很多灵活的写法,可以参考官方文档。

3. Layout细节

(1) import
1) 在标签中,import 一些class,就像在java 代码中一样
如: <import type="android.view.View"/>
2) 当类名过长或者有类名称冲突,其中一个类可以重命名一个别名

<import type="com.grandstream.gsmarket.R.string" alias="Strings"/>

<import type="android.view.View"/>
<import type="com.example.real.estate.View"
        alias="EsView"/>

3) 也可以在表达式中运用静态属性或方法,使用MyStringUtils.capitalize():

<data>
    <import type="com.example.MyStringUtils"/>
    <variable name="user" type="com.example.User"/>
</data><TextView
   android:text="@{MyStringUtils.capitalize(user.lastName)}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

示例代码

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >
    <data>

        <variable
            name="viewmodel"
            type="com.grandstream.gsmarket.appdetail.AppDetailItemViewModel" />

        <import type="android.view.View"/>

        <import type="com.grandstream.gsmarket.R.string" alias="Strings"/>
    </data>

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <android.support.v7.widget.AppCompatTextView
                        android:id="@+id/download_count_text"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="15dp"
                        android:singleLine="true"
                        android:textColor="#999999"
                        android:textSize="36px"
                        android:text='@{viewmodel.getContext().getString(Strings.download) + viewmodel.downloadCount}'/>
                </LinearLayout>

(2)可以定义多个标签
这些variable变量在编译时会进行类型检查,如果一个variable实现了Observable接口或是一个Observable的collection,那就需要在type中声明;如果不是一个Observable的实现,那么该variable就不会被观察到.

<data>

        <import type="android.view.View" />

        <variable
            name="view"
            type="com.grandstream.gsmarket.apps.ApkListFragment" />

        <variable
            name="viewmodel"
            type="com.grandstream.gsmarket.apps.AppsViewModel" />

    </data>

(3)自定义绑定 class names

默认情况下,基于布局文件的名称而生成绑定类,开头大写,然后移除下划线,再加上后缀”Binding”。这个类将被放置在一个数据绑定包中,该包位于moudle包下。例如, 布局文件contact_item.xml将生成ContactItemBinding。如果moudle的包名为com.example.my.app, 那么它将被放置在com.example.my.app.databinding下,通过调整data元素的class属性,绑定类可以重命名或放置在不同的包。

<data class="ContactItem">
    ...
</data>

这会生成在moudle下的databinding包下,如果要生成moudle包下,可以使用”.”前缀:

<data class=".ContactItem">
    ...
</data>

在下面这种情况下,ContactItem直接生成在模块包下。可以使用任何完整的包路径:

<data class="com.example.ContactItem">
    ...
</data>

(4)include
variables可以传递给使用了include标签的子布局中,如

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </LinearLayout>
</layout>

如上,在name.xml和contract.xml中都可以使用变量user了

不支持在merge下直接使用include的情形。

(5)表达式语言
1)共同的特征
表达式语言看起来很像Java表达式。如下这些都是相同的:

Mathematical + - / * %
String concatenation +
Logical && ||
Binary & | ^
Unary + - ! ~
Shift >> >>> <<
Comparison == > < >= <=
instanceof
Grouping ()
Literals - character, String, numeric, null
Cast
Method calls
Field access
Array access []
Ternary operator ?:

例:

android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'

2)不支持的操作符

thisnewsuper 如这些,还是只能在java类中使用

3)合并null操作符
如下使用 “??” 操作符

android:text="@{user.displayName ?? user.lastName}"

等价于

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

4)属性引用
如下,user有getLastName(),可以简单引用:

android:text="@{user.lastName}"

5)NullPointerException处理
数据绑定代码会自动检查null值,避免NullPointerException。例如String类型默认为null, Int类型默认0.

6)集合
一般的集合都可以使用”[]”操作符: arrays, lists, sparse lists, and maps。例

<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List&lt;String&gt;"/>
    <variable name="sparse" type="SparseArray&lt;String&gt;"/>
    <variable name="map" type="Map&lt;String, String&gt;"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"

7)字符串引用
如下,可以使用单引号在属性值上,用双引号在字符串字面值上:

android:text='@{map["firstName"]}'

也可以反过来

android:text="@{map[`firstName`}"
android:text="@{map['firstName']}"

8)资源
可以使用正常的访问资源的表达式语法:

android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"

可以为格式字符串和复数提供参数:

android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"

一些资源需要显示的引用

Type Normal Reference Expression Reference
String[] @array @stringArray
int[] @array @intArray
TypedArray @array @typedArray
Animator @animator @animator
StateListAnimator @animator @stateListAnimator
color int @color @color
ColorStateList @color @colorStateList

猜你喜欢

转载自blog.csdn.net/u011897062/article/details/79769269