Android 官方数据绑定框架:DataBinding(AndroidX学习)

·  阅读 394

Android 官方数据绑定框架:DataBinding,AndroidX学习

不是每个人都能成为,自己想要的样子,但每个人,都可以努力,成为自己想要的样子。相信自己,你能作茧自缚,就能破茧成蝶。

什么是DataBinding,为了解决什么问题?

DataBinding是Android推出的一款数据绑定框架,为了解决 Activity / Fragment 之间获取控件 findViewById() 的操作,降低数据之间的耦合性


viewBinding和dataBinding的区别

  • DataBinding仅处理使用 代码创建的数据绑定布局
  • ViewBinding不支持布局变量或布局表达式,因此它不能用于在 XML 中将布局与数据绑定,ViewBinding仅是节省了findview的步骤

导入

导入图(1.1):

android {
  dataBinding {
        enabled = true
    }
}
复制代码

基本使用:引用数据类型

alt + enter(回车)选中Convert to data … layout,将布局改为DataBinding布局
在这里插入图片描述

改完之后简单使用:

activity_bin.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
	<!--        DataBinding自动生成别名   -->
    <data class="DataBinding">
        <import type="demo.ht.com.basequickadpater.beans.UserBean" />
        
		 <!--        变量:UserBean     -->
        <variable
            name="user"
            type="UserBean" />
    </data>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="2000dp"
            android:gravity="center"
            android:orientation="vertical"
            tools:context=".activitys.BinActivity">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.name}" />
        </LinearLayout>
</layout>
复制代码

分析:

  • <data></data > 标签是用来定义变量的,下边代码就是正常的布局
  • <data class=“DataBinding”></data > 自动生成别名(这个不懂不急,下面会详细解释)
  • <import type = “包名”> 引入包名
  • <variable name = “别名” type=“包名”> 用来定义变量,提供下面布局使用

引用流程:

\

UserBean类:

public class UserBean  extends BaseObservable {
    public String name;//共有变量
    private int age;//私有变量
   
	get.. set..
    有参 .. 无参构造 ..
    
    @Bindable  //private 设置数据调用
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
        //private 请求设置数据
        notifyPropertyChanged(BR.age);
    }
}
复制代码

分析:

  • 共有变量:不需要加任何的注释,因为外部直接能够调用,也能够使用到

  • 私有变量:

    • 需要extends 自 BaseObservable
    • 给自身的getter()方法加@Bindable注释,为了DataBinding能够直接调用到
    • 给自身的setter()方法刷新方法 notifyPropertyChanged(id);为了使DataBinding能够设置值

notifyPropertyChanged参数介绍:

DataBinding会自动生成自己的BR控件类,需要获取BR中的对应方法.

\

BinActivity类:

public class BinActivity extends AppCompatActivity {

    private DataBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.activity_bin);
		
		 //设置对象
         binding.setUser(new UserBean("szj", 1));
      }
}
复制代码

分析:

  • 取消掉了最初的 setContentView(id); 加载布局的方法;
  • 使用 DataBindingUtil.setContentView(Activity,加载布局id) 加载布局
  • 这里的返回值需要手动改成对应的值

这里返回的就是刚刚定义的别名
在这里插入图片描述
如果不写别名会怎么样?
在这里插入图片描述
自动生成的Binding 就是以 当前布局取消掉下划线首字母大写+BinDing 来命名的

效果图(2.1):

\

其他类型使用

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
<!--        DataBinding自动生成别名 -->
    <data>
    
        <import type="demo.ht.com.basequickadpater.beans.UserBean" />

        <import type="java.util.ArrayList" />

        <import type="java.util.HashMap" />

        <import type="demo.ht.com.basequickadpater.activitys.BinActivity" />


        <!--        Map 目前只支持基本引用类型     -->
        <variable
            name="hashMap"
            type="HashMap&lt;String, String>" />

        <!--        int     -->
        <variable
            name="listi"
            type="int" />

        <!--        数组 目前只支持基本引用类型     -->
        <variable
            name="users"
            type="String[]" />

        <!--        ArrayList     -->
        <variable
            name="userList"
            type="ArrayList&lt;UserBean>" />

        <!--        UserBean     -->
        <variable
            name="user"
            type="UserBean" />

        <!--        boolean     -->
        <variable
            name="isCheck"
            type="boolean" />

        <!--        点击事件     -->
        <variable
            name="OnClickListener"
            type="BinActivity" />
    </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="2000dp"
            android:gravity="center"
            android:orientation="vertical"
            tools:context=".activitys.BinActivity">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{user.name}" />


            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{String.valueOf(user.age)}" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{userList[listi].name}" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{hashMap[`name`]}" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{users[0]}" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{users[0]}" />

            <TextView
                android:id="@+id/tv1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="@{OnClickListener.onClick}"
                android:text='@{isCheck ? "error" : "ok"}' />

            <TextView
                android:id="@+id/tv2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="@{OnClickListener.onClick}"
                android:text="点击事件" />

        </LinearLayout>

</layout>
复制代码

分析:

  • &lt; :是 < 号,在代码中不能出现<>,因为和布局标签重复了,所以必须使用 &lt;
  • 在调用int类型的时候,不能直接调用,必须使用String.valueOf(int)来包裹,因为文字不支持int类型的.
  • 使用List 和 数组直接 list[int] 即可
  • 使用map集合hashMap[` key ` ] , 切记不是单引号( ’ )
  • 使用 boolean时,可以使用三目运算符,默认为false

BinActivity类:

	binding = DataBindingUtil.setContentView(
                this,
                R.layout.activity_bin
        );
        
		//ArrayList集合
        ArrayList<UserBean> userList = new ArrayList<UserBean>() {
            {
                add(new UserBean("张三", 23));
                add(new UserBean("王五", 23));
                add(new UserBean("赵六", 23));
                add(new UserBean("武大", 23));
            }
        };
        
		//hashMap
        HashMap<String, String> hashMap = new HashMap<String, String>() {
            {
                put("name", "HashMap");
            }
        };

        String[] s = new String[1];
        s[0] = new String("User数组");
        //设置数组
        binding.setUsers(s);

        //设置int
        binding.setListi(1);


        //设置对象
        binding.setUser(new UserBean("szj", 1));

        //设置List
        binding.setUserList(userList);

        //设置Map
        binding.setHashMap(hashMap);
复制代码

这里的setXXX就是对应的布局中的

\

效果图(2.3):

点击事件

activity_bin.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
<!--        DataBinding自动生成别名 -->
    <data>

        <import type="demo.ht.com.basequickadpater.activitys.BinActivity" />

        <!--        点击事件     -->
        <variable
            name="OnClickListener"
            type="BinActivity" />

    </data>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="2000dp"
            android:gravity="center"
            android:orientation="vertical"
            tools:context=".activitys.BinActivity">

            <TextView
                android:id="@+id/tv1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="@{OnClickListener.onClick}"
                android:text='@{isCheck ? "error" : "ok"}' />

            <TextView
                android:id="@+id/tv2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="@{OnClickListener.onClick}"
                android:text="点击事件" />
        </LinearLayout>
</layout>
复制代码

BinActivity类:


 //设置Text监听
binding.setOnClickListener(this);

 public void onClick(View view){
        if (view.getId() ==R.id.tv1) {
            Toast.makeText(this, "点击了tv1", Toast.LENGTH_SHORT).show();

        }else{
            Toast.makeText(this, "点击了tv2", Toast.LENGTH_SHORT).show();
        }
    }
复制代码

效果图(2.4):

Fragment绑定数据

fragment_binding.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="demo.ht.com.basequickadpater.beans.UserBean"/>

        <variable
            name="userBean"
            type="UserBean" />

        <variable
            name="click"
            type="demo.ht.com.basequickadpater.fragments.BindingFragment" />
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/teal_200"
        tools:context=".fragments.BindingFragment">

        <TextView
            android:onClick="@{click.onTextClick}"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textAllCaps="false"
            android:textSize="30dp"
            android:gravity="center"
            android:text="@{userBean.name}" />
    </FrameLayout>
</layout>
复制代码

BindingFragment:

public class BindingFragment extends Fragment {


    private FragmentBindingBinding inflate;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        //Fragment
        inflate = DataBindingUtil.inflate(inflater, R.layout.fragment_binding, container, false);

        inflate.setUserBean(new UserBean("Fragment页面 "));

        inflate.setClick(this);

        return inflate.getRoot();
    }
    public void onTextClick(View view){
        Toast.makeText(getActivity(), "Fragment页面", Toast.LENGTH_SHORT).show();
    }
}
复制代码

DataBindingUtil.inflate参数分析:

  • LayoutInflater:布局管理
  • int: 显示布局id
  • ViewGroup:父布局(ViewGroup)
  • boolean: 默认为 false

Fragment和Activity只有获取实例不一样,其他的都是一样的操作!

效果图(2.5):

RecyclerView绑定数据

activity_bin.xml:

<androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rel"
                android:layout_width="match_parent"
                android:layout_height="300dp"/>
复制代码

BinActivity:

		 private ArrayList<UserBean> userBeans = new ArrayList<>();
		 
		 RecyclerView rel = findViewById(R.id.rel);

         rel.setLayoutManager(new LinearLayoutManager(this));

        //初始化数据
        initItem();

        rel.setAdapter(new MyAdapter(userBeans,this));

	/**
     * 初始化数据
     */
    private void initItem() {
        for (int i = 0; i < 50; i++) {
            userBeans.add(new UserBean("数据: " + i));
        }
    }
复制代码

这里的代码都很简单,直接来看适配器吧~

item_layout.xml:适配器布局

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="userBean"
            type="demo.ht.com.basequickadpater.beans.UserBean" />
    </data>

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

        <TextView
            android:id="@+id/tv"
            android:text="@{userBean.name}"
            android:textSize="30dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
</layout>
复制代码

MyAdapter适配器:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    public List<UserBean> list;
    public Context context;


    public MyAdapter(List<UserBean> list, Context context) {
        this.list = list;
        this.context = context;
    }

    @NonNull
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ItemLayoutBinding inflate = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.item_layout, parent, false);
        ViewHolder viewHolder = new ViewHolder(inflate.getRoot());
        viewHolder.setInflate(inflate);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
        holder.getInflate().setVariable(BR.userBean,list.get(position));

        //当数据改变时,binding会在下一帧去改变数据,如果我们需要立即改变,就去调用executePendingBindings方法。
        holder.getInflate().executePendingBindings();
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {
        private ItemLayoutBinding inflate;

        public ItemLayoutBinding getInflate() {
            return inflate;
        }

        public void setInflate(ItemLayoutBinding inflate) {
            this.inflate = inflate;
        }

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
}
复制代码

onCreateViewHolder方法:

  • 该方法是用来设置子条目布局的,和Fragment设置布局的方法一样,使用DataBindingUtil.inflate来设置布局,
  • 通过ViewHolder来保存当前的状态
  • 在onBindViewHolder通过获取ViewHolder中的状态来设置当前值

总说周知:
在RecyclerView适配器中,首先执行的值getItemCount()方法,其次是onCreateViewHolder()用来设置布局,最后才是onBindViewHolder()用来绑定数据

如果大家觉得这种办法实在是太麻烦,推荐大家使用万能适配器

有不懂的记得在评论区留言哦~

设置图片

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
<!--        DataBinding自动生成别名 -->
    <data>
    
 	    .....
 	    
        <!--        Image图片     -->
        <variable
            name="imageUrl"
            type="demo.ht.com.basequickadpater.beans.ImageBean" />

    </data>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="2000dp"
            android:gravity="center"
            android:orientation="vertical"
            tools:context=".activitys.BinActivity">	
					.....
            <ImageView
                app:url="@{imageUrl.url}"
                android:layout_width="match_parent"
                android:layout_height="100dp"/>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
复制代码

ImageBean 类:

public class ImageBean   extends BaseObservable {

    @Bindable
    private String  url;

    public ImageBean(String url) {
        this.url = url;
    }
    
    @BindingAdapter("bind:url")  //bind后的名字任意起,注方法一定要为静态,否则报错
    public static void getImage(ImageView view, String url){
        Glide.with(view.getContext())
         .load(url)
         .apply(new RequestOptions().placeholder(R.mipmap.ic_launcher))
         .into(view);
    }
}
复制代码

分析:

  • 这里的getImage()必须为静态,不需要调用!
  • 需要添加注解 @BindingAdapter(“bind:XXX”)

这里的url对应的布局中的app:url:
在这里插入图片描述

BinActivity类:

ImageBean imageBean = new ImageBean("https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top-e3b63a0b1b.png");

binding.setImageUrl(imageBean);
复制代码

效果图(2.6):

获取当前时间

和ImageView使用类似

activity_bin.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
  		 ....
        <!--        获取当前时间     -->
        <variable
            name="date"
            type="java.util.Date" />

    </data>
			...
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{date}" />
			...
</layout>
复制代码

DateBean类:

public class DateBean {
    //获取当前日期
    @BindingConversion
    public static String convertDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        return sdf.format(date);
    }
}
复制代码

分析:

  • 不需要调用,添加注释后会自动走这里
  • 一定要静态!

BinActivity:

binding.setDate(new Date());
复制代码

效果图(2.6):

\

完整代码

去博主主页查看更多

原创不易,您的点赞就是对我最大的支持哦~

分类:
Android
标签: