【Android】DataBinding 库(MVVM 设计模式)

1,691 阅读3分钟
  • 使用上面的代码实现了UI的更新你就满足了?其实官方为我们提供了更加简便的方式,使User继承BaseObservable,代码如下

    public class User extends BaseObservable {
      private String firstName;
      private String lastName;
    
      public User(String firstName, String lastName) {
          this.firstName = firstName;
          this.lastName = lastName;
      }
      @Bindable
      public String getFirstName() {
          return this.firstName;
      }
      @Bindable
      public String getLastName() {
          return this.lastName;
      }
    
      public void setLastName(String lastName) {
          this.lastName = lastName;
          notifyPropertyChanged(BR.lastName);
      }
    
      public void setFirstName(String firstName) {
          this.firstName = firstName;
          notifyPropertyChanged(BR.firstName);
      }
    }

    只要user发生变化,就能达到改变UI的效果。在MainActivity中只要调用以下代码

    user.setFirstName("Com");

    有了BaseObservable就够了?不不不,我比较懒,不想写那么多@Bindable和notifyPropertyChanged。万一里面有几十个属性,那不写哭起来?而且还有可能写丢了。
    Data Binding的开发者贴心得为我们准备了一系列的ObservableField,包括: ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat,ObservableDouble, 以及 ObservableParcelable看看它们的用法
    ObservableField的使用
    1、创建User2

    public class User2 {
      public final ObservableField firstName = new ObservableField<>();
      public final ObservableField lastName = new ObservableField<>();
      public final ObservableInt age = new ObservableInt();
      public final ObservableBoolean isStudent = new ObservableBoolean();
    }

    这类里面没有Get/Set。
    2、布局文件

          
          
          

    3、MainActivity中

          mUser2 = new User2();
          binding.setUser2(mUser2);
          mUser2.firstName.set("Mr");
          mUser2.lastName.set("Bean");
          mUser2.age.set(20);
          mUser2.isStudent.set(false);

    这里new了一个User2对象后,直接就绑定了。之后只要mUser2中的数据发生变化,UI也会随之更新。
    除了这几个Map跟List也是必不可少的,Data Binding为我们提供了 ObservableArrayMapObservableArrayList
    ObservableArrayMap的使用

    ObservableArrayMap user = new ObservableArrayMap<>();
    user.put("firstName", "Google");
    user.put("lastName", "Inc.");
    user.put("age", 17);

    ObservableArrayList的使用

    ObservableArrayList user = new ObservableArrayList<>();
    user.add("Google");
    user.add("Inc.");
    user.add(17);
    

    在布局中使用中文时,编译无法通过。

    android:text='@{user2.isStudent?"学生":"非学生"}'

    感谢吕檀溪同学的解决方案:
    这是java环境的问题,在系统环境变量中增加一个变量,变量名为: JAVA_TOOL_OPTIONS, 变量值为:-Dfile.encoding=UTF-8,保存。要重启一次电脑,中文就解决了,但是在某些地方,编译的时候控制台会出现部分乱

  • 在RecyclerView或ListView中使用

    前面说了那么多基础的用法,可还是不能达到我们的需求。几乎在每个app中都有列表的存在,RecyclerView或ListView,从上面所说的似乎还看不出Data Binding在RecyclerView或ListView中是否也能起作用。(用屁股想也知道,Google的开发团对怎么可能会犯这么低级的错误)。下面以RecyclerView为例子:
    1、直接看Item的布局(user_item.xml):

    
    
      
          
      
      
          
          
          
          
          
      
    

    2、RecyclerView的数据绑定是在Adapter中完成的,下面看看Adapter(这里使用了一个Adapter,如果你在使用的时候发现RecyclerView的动画没了,去这里寻找答案)

    public class MyAdapter extends RecyclerView.Adapter {
    
      private List mData = new ArrayList<>();
    
      public MyAdapter(List data) {
          this.mData = data;
      }
    
      @Override
      public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
          return MyHolder.create(LayoutInflater.from(parent.getContext()), parent);
      }
    
      @Override
      public void onBindViewHolder(MyHolder holder, int position) {
          holder.bindTo(mData.get(position));
      }
    
      @Override
      public int getItemCount() {
          if (mData == null)
              return 0;
          return mData.size();
      }
    
      static class MyHolder extends RecyclerView.ViewHolder {
          private UserItemBinding mBinding;
    
          static MyHolder create(LayoutInflater inflater, ViewGroup parent) {
              UserItemBinding binding = UserItemBinding.inflate(inflater, parent, false);
              return new MyHolder(binding);
          }
    
          private MyHolder(UserItemBinding binding) {
              super(binding.getRoot());
              this.mBinding = binding;
          }
    
          public void bindTo(User2 user) {
              mBinding.setUser2(user);
              mBinding.executePendingBindings();
          }
    
      }
    }

    3、最后在布局和MainActivity中的使用跟平时的用法一样
    布局中加入RecyclerView:

          

    MainActivity中:

          List data = new ArrayList<>();
          for (int i = 0; i < 20; i++) {
              User2 user2 = new User2();
              user2.age.set(30);
              user2.firstName.set("Micheal " + i);
              user2.lastName.set("Jack " + i);
              data.add(user2);
          }
          RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
          LinearLayoutManager layoutManager = new LinearLayoutManager(
                  this, LinearLayoutManager.VERTICAL, false);
          recyclerView.setLayoutManager(layoutManager);
          recyclerView.setAdapter(new MyAdapter(data));

    这样就可以了。
    不过,在自动生成的ActivityMainBinding中,我们可以看到根据RecyclerView的id,会自动生成一个recyclerView。



    所以在MainActivity中,我们可以不用findViewById,直接使用binding.recyclerView。

          LinearLayoutManager layoutManager = new LinearLayoutManager(
                  this, LinearLayoutManager.VERTICAL, false);
          binding.recyclerView.setLayoutManager(layoutManager);
          binding.recyclerView.setAdapter(new MyAdapter(data));

    来看看效果吧:


    RecyclerView