博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android官方数据绑定框架DataBinding(二)
阅读量:6079 次
发布时间:2019-06-20

本文共 7682 字,大约阅读时间需要 25 分钟。

hot3.png

六、 表达式 

短暂的幸福时光,我们还是要告别java代码了,继续回到xml中,这一块,我们来学习一下表达式,什么?这玩意在xml中还支持表达式!

还记得上面我们定义了一个boolean的变量没有用到,这里我们就用到了,看好android:text,这里是一个三元表达式,如果error是true,则text就是error,否则是ok。这里还支持null合并操作,什么是null合并,相信看一眼你就知道了

android:text='@{str==null ?? "not null"}'

简单解释一下,如果str是null,text的值就是str本身,否则就是”not null”。 

它还支持一下表达式:

  • Mathematical + - / * %

  • String concatenation +

  • Logical && ||

  • Binary & | ^

  • Unary + - ! ~

  • Shift >> >>> <<

  • Comparison == > < >= <=

  • instanceof

  • Grouping ()

  • Literals - character, String, numeric, null

  • Cast

  • Method calls

  • Field access

  • Array access []

  • Ternary operator ?:

但是它不支持一下表达式:

  • this

  • super

  • new

  • Explicit generic invocation

七、 其他遗漏点 

说到这里,xml中的事情基本算完了,但是还有几个小地方没有说,顺便说一下。 
1. 设置别名 
假如我们import了两个相同名称的类咋办?别怕,别名来拯救你!例如:

...      
    
  
  
  
  ...

自定义Binding名称 

还记得系统为我们生成好的那个binding类名吗?如果只能使用那样的是不是有点太暴力了?好在google对我们还算友好了,允许我们自定义binding名称,定制名称也很简单,就是给data一个class字段就ok。 
例如:

...

那么:DataBindingUtils.setContentView返回的binding类就是:你的应用包名.Custom

八、事件绑定 

大家都知道,在xml中我们可以给button设置一个onClick来达到事件的绑定,现在DataBinding也提供了事件绑定,而且不仅仅是button。 
来看一下:

      
          
          
      
        
          
        

定义了一个EventHandlers类型的handlers变量,并在onClick的时候执行EventHandlershandleClick方法。 

继续看看EventHandlers是怎么写的。

public class EventHandlers {      public void handleClick(View view) {          Toast.makeText(view.getContext(), "you clicked the view", Toast.LENGTH_LONG).show();      }  }

很简单,就是简单的Toast了一下,这里要注意的是,handlerClick方法需要一个View的参数。

九、 数据对象 

我们学会了通过binding为我们的变量设置数据,但是不知道你有没有发现一个问题,当我们数据改变的时候会怎样?数据是跟随着改变呢?还是原来的数据 呢?这里告诉你:很不幸,显示的还是原来的数据?那有没有办法让数据源发生变化后显示的数据也随之发生变化?先来想想ListView是怎么做的, ListView的数据是通过Adapter提供的,当数据发生改变时,我们通过notifyDatasetChanged通过UI去改变数据,这里面的原理其实就是内容观察者,庆幸的是DataBinding也支持内容观察者,而且使用起来也相当方便!

BaseObservable 

我们可以通过Observable的方式去通知UI数据已经改变了,当然了,官方为我们提供了更加简便的方式BaseObservable,我们的实体类只需要继承该类,稍做几个操作,就能轻松实现数据变化的通知。如何使用呢? 首先我们的实体类要继承BaseObservale类,第二步在Getter上使用注解@Bindable,第三步,在Setter里调用方法notifyPropertyChanged,第四步,完成。就是这么简单,下面我们来实际操作一下。 
首先定义一个实体类,并继承BaseObservable

public class Student extends BaseObservable {      private String name;        public Student() {      }        public Student(String name) {          this.name = name;      }        @Bindable      public String getName() {          return name;      }        public void setName(String name) {          this.name = name;          notifyPropertyChanged(org.loader.app4.BR.name);      }  }

观察getName方法,我们使用了@Bindable注解,观察setName,我们调用了notifyPropertyChanged方法,这个方法还需要一个参数,这里参数类似于R.java,保存了我们所有变量的引用地址,这里我们使用了name。 

再来看看布局文件。

      
          
          
          
            
  

不多说了,我们给TextView设置了文本,还有点击事件。Activity,

public class MainActivity extends AppCompatActivity {        private Student mStu;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          org.loader.app4.Custom binding = DataBindingUtil.setContentView(this,                  R.layout.activity_main);          mStu = new Student("loader");          binding.setStu(mStu);          binding.setClick(this);      }        public void click(View view) {          mStu.setName("qibin");      }  }

这段代码,首先显示的是loader,当我们点击TextView时,界面换成qibin。

ObservableFields家族 

上面使用BaseObservable已经非常容易了,但是google工程师还不满足,继续给我们封装了一系列的ObservableFields,这里有ObservableFieldObservableBoolean,ObservableByte,ObservableChar,ObservableShort,ObservableInt,ObservableLong,ObservableFloat,ObservableDouble,ObservableParcelable
ObservableFields的使用方法就更加简单了,例如下面代码,

public class People {      public ObservableField
 name = new ObservableField<>();      public ObservableInt age = new ObservableInt();      public ObservableBoolean isMan = new ObservableBoolean();  }

很简单,只有三个ObservableField变量,并且没有getter和setter,因为我们不需要getter和setter。 

在xml中怎么使用呢?

      
            
            
          
            
          
        

也很简单,直接使用变量,那怎么赋值和取值呢?这些ObservableField都会有一对getset方法,所以使用起来也很方便了:

...  mPeople = new People();  binding.setPeople(mPeople);  mPeople.name.set("people");  mPeople.age.set(19);  mPeople.isMan.set(true);  ...

也不多说了。

Observable Collections 

既然普通的变量我们有了ObservableFields的分装,那集合呢?当然也有啦,来看着两个:ObservableArrayMap,ObservableArrayList。使用和普通的Map、List基本相同,直接看代码:

      
          
" />          
" />            
          
          
        

在布局中,使用方式和普通的集合一样,如果看不太懂,可以往上翻博客,看上面的集合是怎么使用的。 

在来看java文件,怎么设置数据,

ObservableArrayMap
 map = new ObservableArrayMap<>();  ObservableArrayList
 list = new ObservableArrayList<>();  map.put("name", "loader or qibin");  list.add("loader!!!");  binding.setMap(map);  binding.setList(list);

太简单了,简直和ListMap使用方法一模一样!!!

十、inflate 
不知道大家注意没有,上面的代码我们都是在activity中通过DataBindingUtil.setContentView来加载的布局的,现在有个问题了,如果我们是在Fragment中使用呢?Fragment没有setContentView怎么办?不要着急,Data Binding也提供了inflate的支持! 
使用方法如下,大家肯定会觉得非常眼熟。

MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);  MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);

接下来,我们就尝试着在Fragment中使用一下Data Binding吧。 

首先还是那个学生类,Student

public class Student extends BaseObservable {      private String name;      private int age;        public Student() {      }        public Student(int age, String name) {          this.age = age;          this.name = name;      }        @Bindable      public int getAge() {          return age;      }        public void setAge(int age) {          this.age = age;          notifyPropertyChanged(org.loader.app5.BR.age);      }        @Bindable      public String getName() {          return name;      }        public void setName(String name) {          this.name = name;          notifyPropertyChanged(org.loader.app5.BR.name);      }  }

继续,activity的布局

        
    

activity的代码,

public class MainActivity extends AppCompatActivity {        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          getSupportFragmentManager().beginTransaction()                  .replace(R.id.container, new MyFragment()).commit();      }  }

重点来了,我们这里data binding的操作都放在了fragment里,那么我们先来看看fragment的布局。

      
          
          
          
              
          
            
        

两个TextView分别绑定了Student的name和age字段,而且给name添加了一个点击事件,点击后会调用Fragment的click方法。我们来迫不及待的看一下Fragment怎么写:

public class MyFragment extends Fragment {        private Student mStu;        @Nullable      @Override      public View onCreateView(LayoutInflater inflater,                               ViewGroup container, Bundle savedInstanceState) {          org.loader.app5.Custom binding = DataBindingUtil.inflate(inflater,                  R.layout.frag_layout, container, false);          mStu = new Student(20, "loader");          binding.setStu(mStu);          binding.setFrag(this);          return binding.getRoot();      }        public void click(View view) {          mStu.setName("qibin");          mStu.setAge(18);      }  }

onCreateView中, 不同于在Activity中,这里我们使用了DataBindingUtil.inflate方法,接受4个参数,第一个参数是一个 LayoutInflater对象,正好,我们这里可以使用onCreateView的第一个参数,第二个参数是我们的布局文件,第三个参数是一个 ViewGroup,第四个参数是一个boolean类型的,和在LayoutInflater.inflate一样,后两个参数决定了是否想container中添加我们加载进来的布局。 

下面的代码和我们之前写的并无差别,但是有一点,onCreateView方法需要返回一个View对象,我们从哪获取呢?ViewDataBinding有一个方法getRoot可以获取我们加载的布局,是不是很简单? 
来看一下效果:

转载于:https://my.oschina.net/fightingmylife/blog/630826

你可能感兴趣的文章
ASP.NET MVC中从前台页面视图(View)传递数据到后台控制器(Controller)方式
查看>>
lintcode:next permutation下一个排列
查看>>
一个想法(续二):换个角度思考如何解决IT企业招聘难的问题!
查看>>
tomcat指定配置文件路径方法
查看>>
linux下查看各硬件型号
查看>>
epoll的lt和et模式的实验
查看>>
Flux OOM实例
查看>>
07-k8s-dns
查看>>
Android 中 ListView 分页加载数据
查看>>
oracle启动报错:ORA-00845: MEMORY_TARGET not supported on this system
查看>>
Go方法
查看>>
Dapper丶DapperExtention,以及AbpDapper之间的关系,
查看>>
搞IT的同学们,你们在哪个等级__那些年发过的帖子
查看>>
且谈语音搜索
查看>>
MySQL数据库导入导出常用命令
查看>>
低版本Samba无法挂载
查看>>
Telegraf+Influxdb+Grafana构建监控平台
查看>>
使用excel 展现数据库内容
查看>>
C#方法拓展
查看>>
MySql.Data.dll的版本
查看>>