安卓 DataBingding详解

DataBingding这个东西是15年推出的一个框架,去年尝试使用了一下,感觉不是很好用,包括IDE的兼容也不是很好,所以最后放弃,一年左右没有动过也忘得差不多了,不过最近谷歌退出了一个新的架构模式AAC(Android Architecture Components),研究了一下发现这个搭配DataBingding一起使用简直很美味啊,包括官方的Demo也是这么干的,所以重新学习了一下该框架,在此做个总结加深印象,至于AAC就不多说,还没有完全摸透,官方链接:https://developer.android.google.cn/develop/index.html

一,DataBingding好处

  1,moudle与ViewD的几乎完全解耦

  2,节省大量无脑力代码,包括findId,adapter,setOnClick()....等
  
  3,据说布局的性能优于findviewbyId

  4,结合AAC对app的生命周期的一系列操作更加便捷

  .....

当然,有好处必然也会有一些坏处

1,xml的赋值方法,对于不熟悉,或者不是很熟悉的人来说,代码阅读起来会很头疼,代码量大的时候会显得很混乱,除了databingding常用者,或者代码开发者来说,比较恶心

2,个人感觉出现问题不是很好定位(比如说偶尔的xml忘记导包,导致编译错误等等)

3,IDE偶尔会抽风

不过综合起来,如果你已经熟练使用DataBingding,个人觉的马上行动起来,他的好处远远大于他的坏处.

二,基本使用

此类教程网上N多,多少无义,直接来到正题,
你需要在你要使用的这个Acitivity或者fragment的布局最外层嵌套一层layout,然后在laout正配置你需要用到的一系列东西,如下代码,这个是布局是一个列表的item,关于列表稍后再说,xml中配置相关的说明在下面代码中已经做了详细说明,请注意注释的文字说明.


  //将你N多配置写在data标签下
    
        /**
        import即使字面意思导包的意思,这个很常用,具体有俩种理解吧:
        1,比如说如果你有一个实体类叫做User,但是那你在下面需要配置很多个User的变量user1,user2....
        你也可以每个变量都写上这个User的全路径,不过这么做很不好,建议直接导包.然后在创建变量的时候Type
        写上这个类名即可,当然如果类名有重复,我们是课已自己定义一个别名的,在你导入的包的后面加上
        alias="user"即可
        2,比方说如下的textView你要使用一个系统的东西Color,你如果不导包的话编译是会出错的,所以你使用系统的
        必须导包(这种情况有很多,Color,View等等...),当然有个包是例外的,就是java的lang包,如Srting类...
      */
        

        /**
        这个就像他的字面意思,变量,variable是你为这个xml定义的一个个变量.如下,你需要给它起一个名字name,
        然后你需要为他指定一个type,这个type可以使你上面导包的类名,也可以是一个类的全类名,也可是是你导包
        时候设置的别名,variable支持后多类型,比如String,int.....
        */
        
        
          
           
           
          
          
          
        /**
        下面这些是某博客说定义list,map的key,其实这写也只是一个变量,和上面的没有任何区别,你把它当作key
        它就是key,你把它当作一个int变量或者一个String变量都是可以的,也可以这么理解,list的索引是一个int,
        所以我们定义一个int,起个名字叫做index而已,没有别的.
        */
          
          
          
    
    

        
    


三,关于xml中的说明基本就是上面这么多,下面是几点注意事项

 1,@{user.firstName} 像这种情况,其实是调用的user的getFirstName,所以,在你不实用ObservableField这些包装类的情况下你必须要重写getFirstName

 2,同理你如果要使用一个方法的话,这个方法也必须是public修饰的,使用方法有俩中写法,   android:onClick="@{user.show}",像这样的,这个方法必须没有参数,或者有参数View,有参数View的一般都是绑定事件,多用在点击事件中.android:onClick="@{user.show()}"这也是一种写法,就是把函数后面的俩括号加上,而且方法是可以传递参数的

 3,android:text='@{user.firstName+"liudehua"}'  如果你要在表达式中引入一个字符串的时候,请这样写,注意引号.

在java代码中的用法
系统会自动为我们生成一个根据你这个Activity或者fragment名字的ViewDataBinding的子类,也就是下面代码中的ActivityMainBinding,然后我们就可以获取数据(网络获取,数据库获取等等)然后调用setUser设置我们xml中定义的变量,系统会根据你xml中定义的variable 的name属性生成一堆set方法,你可以更具自己情况去设置.

   ActivityMainBinding viewDataBinding = DataBindingUtil.setContentView(this,   R.layout.activity_main);
   user.setFirstName("1111111111");
   viewDataBinding.setUser(user);

当我们调用set方法的时候,xml中相对应的值就会改变,然后ui也会发生变化,当然你也可以根据id来设置,只需要为我们的控件设置一个id,viewDataBinding 中就会保存一个这个id的变量,你可以做一些操作

四,然后此时基本就可以使用databingding了,不过之前我们有一个概念叫做双向绑定,如何做到呢?现在的情况是我们把一个user设置给bingding,但是如果我们值设置一次,之后的user的值无论如何变化都是不会改变ui的,这个时候谷歌爸爸为我们提供了几个东西:

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

public class User extends BaseObservable {  
    private String firstName;  
  
    public User () {  
    }  
  
    public Student(String name) {  
        this.name = name;  
    }  
  
    @Bindable  
    public String getFirstName() {  
        return name;  
    }  
  
    public void FirstName(String name) {  
        this.firstName= firstName;  
        //BR是类是java的R文件的一个东西,它保存有我们所有字段
        notifyPropertyChanged(BR.firstName);  
    }  
}  

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

public class User {
    public   ObservableField firstName=new ObservableField<>();
    public ObservableInt age = new ObservableInt();  
}

这里我们就不用重写get方法了,因为内部已经替我们实现了,而且也不用我们调用notifyPropertyChanged了,个人建议使用这中方式,第一中的代码入侵太大.

五,recycleview的用法
这个东西说实话在listview中实在很好用,我们直接来看怎们用,首先来一个布局,就是我们开局时候的布局代码,
然后来看adapter怎们用:
1,onCreateViewHolder方法中我们来搞一个ViewDataBinding 出来
2,然后正常的写一个holder,
3,让这个holder保存一个ViewDataBinding ,因为这个holder是列表item的holder,所以保存的也是item布局的ViewDataBinding ,布局不匹配是会出大问题的.
4,为这个holder的ViewDataBinding 创建get,set方法方便获取设置
5,在onBindViewHolder中设置布局中需要的变量
6,最后在onBindViewHolder中调用 bingDing.executePendingBindings(),次方法是立即刷刷新界面,正常情况是在下一帧刷新.

public class MainAdapter  extends RecyclerView.Adapter{

    private Context context;
    private ArrayList list=new ArrayList<>();

    public MainAdapter(Context context) {
        this.context = context;
    }

    @Override
    public MainHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.activity_main_item, parent, false);
        MainHolder mainHolder = new MainHolder(binding.getRoot());
        mainHolder.setBingDing(binding);
        return mainHolder;
    }

    @Override
    public void onBindViewHolder(MainHolder holder, int position) {
        ViewDataBinding bingDing = holder.getBingDing();
        bingDing.setVariable(BR.user,list.get(position));
        bingDing.setVariable(BR.position,position);
        bingDing.executePendingBindings();
    }

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

    public void setData(ArrayList data) {
        list.clear();
        list.addAll(data);
    }

    public  static class MainHolder extends RecyclerView.ViewHolder{

        private ViewDataBinding bingDing;

        public MainHolder(View itemView) {
         super(itemView);
     }

        public ViewDataBinding getBingDing() {
            return bingDing;
        }

        public void setBingDing(ViewDataBinding bingDing) {
            this.bingDing = bingDing;
        }
    }
}

然后是activity的使用

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding viewDataBinding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        MainAdapter mainAdapter = new MainAdapter(this);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL,false);
        ArrayList users = initData();
        mainAdapter.setData(users);
        viewDataBinding.rl.setLayoutManager(linearLayoutManager);
        viewDataBinding.rl.setAdapter(mainAdapter);
        User user = new User();
        users.add(user);
        mainAdapter.setData(users);
        users.get(10).setFirstName("hahahahahah");
    }

    private ArrayList initData() {
        ArrayList users = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            User user = new User();
            user.setFirstName("学生"+i+"号");
            users.add(user);
        }
        return  users;
    }
    
}

我们发现代码是不是简洁了很多啊.

六,其他用法

下面这中情况可能我们会遇到,当我们布局中有个imageview的时候貌似databingding就失灵了,因为我们图片都是从网络加载的啊,别担心dataBingding为我们准备了一个东西来解决这类问题

比如布局如下:我们为ImageView 设置了这么一个属性 app:image="@{imageUrl}
这是怎们回事,请往下看

  
      
          
      
  
      
 

我们需要定义这么一个方法,你可以专门搞个BingdingUtils 方此类的方法,
在这个方法中我们用到一个注解BindingAdapter,这个就是来自定义一个get方法,方法中我们具体实现这个属性的内容(从网络上加载一个图片设置给imageView),xml中用到的在定义属性app:image就是我们 @BindingAdapter({"bind:image"}) 定义的这个,这是一个数组,所以呢可以定义很多个属性来用这个方法,然后即使在xml中使用 app:image="@{imageUrl}"这样就可以把这个网络地址的图片设置给我们的ImageView ,当然你需要在java代码中set这个值.

public class BingdingUtils {  
    @BindingAdapter({"bind:image"})  
    public static void imageLoader(ImageView imageView, String url) {  
        ImageLoaderUtils.getInstance().displayImage(url, imageView);  
    }  
} 

还有一种情况比如我们要设置text属性,而拿到的值却不是一个string,或者说我们想在所有的text设置之前做一些操作,等等...这个属性是自带的我们没法去自定义一个BindingAdapter,这种情况要怎们做?
谷歌还为我们提供了一个东西叫做Converter,就是字面的意思转换器

就像下面的代码一样,我们创建一个转换器,用BindingConversion注解来标准,这个东西是统一性的,只要你用databingding设置的内容的类型是这个方法的参数类型,比如下面的这个方法就是String,呢设置的这个内容就会被转换,所以这个也要看好了再用,
不过这个一般可以解决很多问题.


public class MainConverter {
    @BindingConversion
    public static String convertDate(String string) {

        return string+"fule ";
    }
}

以上就是databing大大小小的一些用法,当然还需要在项目中去实操才能熟练使用.

你可能感兴趣的:(安卓 DataBingding详解)