安卓 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中配置相关的说明在下面代码中已经做了详细说明,请注意注释的文字说明.

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

        /**
        这个就像他的字面意思,变量,variable是你为这个xml定义的一个个变量.如下,你需要给它起一个名字name,
        然后你需要为他指定一个type,这个type可以使你上面导包的类名,也可以是一个类的全类名,也可是是你导包
        时候设置的别名,variable支持后多类型,比如String,int.....
        */
        <variable
            name="user"
            type="luo.com.shiyu.bingdingdemo.User"/>
        <variable
            name="position"
            type="Integer"/>
        <variable  
            name="str"  
            type="String"/>  
         <variable  
            name="error"  
            type="boolean"/>  
         <variable  
            name="num"  
            type="int" />  
        <variable  
            name="list"  
            type="ArrayList<String>" />  
        <variable  
            name="map"  
            type="HashMap<String, String>" />  
        <variable  
            name="array"  
            type="String[]" />  
        /**
        下面这些是某博客说定义list,map的key,其实这写也只是一个变量,和上面的没有任何区别,你把它当作key
        它就是key,你把它当作一个int变量或者一个String变量都是可以的,也可以这么理解,list的索引是一个int,
        所以我们定义一个int,起个名字叫做index而已,没有别的.
        */
        <variable  
            name="listKey"  
            type="int" />  
        <variable  
            name="mapKey"  
            type="String" />  
        <variable  
            name="arrayKey"  
            type="int" />  
    </data>
    <android.support.constraint.ConstraintLayout

        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            /**
            关于使用,就是这种固定的写法,很多文章都讲解的非常细致,包括一些三元表达式等...需要的可以自行查阅,
            基本java代码中的一些表达写法都可以使用,当然不可已new,或者你调用的方法的返回值必须和这个xml属性匹配
            */
            android:text="@{user.firstName}"
            android:textColor="@{position%2==0?Color.RED:Color.BLUE}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </android.support.constraint.ConstraintLayout>
</layout>

三,关于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<String> 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<MainAdapter.MainHolder>{

    private Context context;
    private ArrayList<User> 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<User> 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<User> 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<User> initData() {
        ArrayList<User> 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}
这是怎们回事,请往下看

<layout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:app="http://schemas.android.com/apk/res-auto">  
    <data class=".....User">  
        <variable  
            name="imageUrl"  
            type="String" />  
    </data>  
  
    <ImageView  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        app:image="@{imageUrl}"/>  
</layout> 

我们需要定义这么一个方法,你可以专门搞个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大大小小的一些用法,当然还需要在项目中去实操才能熟练使用.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,231评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,554评论 18 139
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,973评论 4 60
  • 利用周末的时间观赏了《嫌疑人X的献身》,该影片是根据日本推理作家东野圭吾的同名小说改编的悬疑电影,由苏有朋指导,王...
    留思阅读 535评论 0 0
  • 李笑来在天天用英语的讲座 ---为自己打工获得两份收入,一份工资收入,一份自己经验收入--- 笑来老师多次提起他的...
    子非_似是而非阅读 203评论 1 1