Android DataBinding初探

2020-04-08  本文已影响0人  KeHaoo

官方的文档有一点晦涩难读,如果直接看案例也很头疼
今天算是对DataBinding有点初步的了解了,就用几个案例记录一下DataBinding的使用,顺便也是一个分享
先放上谷歌官方文档的DataBinding这一部分的链接,要是想深入了解还是推荐看文档

什么是Databinding

数据绑定库是一种支持库,借助该库,您可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源。
布局通常是使用调用界面框架方法的代码在 Activity 中定义的。

简单的说以前对数据和控件的操作非常繁琐,先要用findViewById()来获取控件,每次数值改变之后,还需要对控件的内容重新进行设置
而这个DataBinding可以把对象和控件绑定,每次对象的值改变了,相对的控件也会刷新,这个就和以前MFC上面的那个绑定变量差不多

DataBinding会根据布局文件自动生成相应的Binding类,在代码中是找不到这个类的,这个类应该是编译阶段生成的,但是我们可以直接去使用
这种布局文件和传统的布局文件有一点点差别,下面放一个案例

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
      <!-- 这里放一些变量的定义,后面会解释 -->
    </data>

     <!-- 把原先的布局文件的内容放到这里(layout的里面) -->
   
</layout>

使用

配置项目

只需要在module里面配置

android {
   ···
        原来已经有的一些配置
   ···

    dataBinding {
        enabled = true
    }
}

一般来说使用DataBinding的话只要你的SDK和Gradle不要太旧的话,基本上都不用管版本什么的,如果遇到了问题就百度一下吧

在Activity里面使用

先写一个很简单的java Bean

public class UserBean {
    private String name; //姓名
    private int age; //年龄

    public UserBean(String name, int age) {
        this.name = name;
        this.age = age;
    }
    ···
此处省略getter和setter方法
    ···
}

我们修改activity的xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <!-- 使用全类名 -->
        <!--
        <variable name = "user" type = "com.kehao.databinding1.bean.UserBean"
            />
            -->
        <!-- import -->
        <import type="com.kehao.databinding1.bean.UserBean"/>
        <variable  name="user" type="UserBean" />


    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

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

        <!--注意:这里age是int类型,必须转化为String,否则会运行时异常-->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(user.age)}" />    
    </LinearLayout>
</layout>

先对这段xml代码中data标签里的内容进行解释

   <variable name = "user" type = "com.kehao.databinding1.bean.UserBean" />

这个就是相当于在布局文件中声明一个变量 等效于java中的 UserBean user,不过并没有new,这个变量具体的引用是靠java代码给他的,后面这个type这么长,是全类名,如果不想写全类名就用import标签这个和java里面的import也差不多
就像这样

   <import type="com.kehao.databinding1.bean.UserBean"/>
   <variable  name="user" type="UserBean"

然后定义里变量之后,在后面的控件中就可以使用啦

<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)}" />   

反正引用的话就是@{这个里面使用java代码}
这样子这个类就和布局文件产生了联系,具体是哪一个变量和控件绑定就需要在Activity里面确定

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        UserBean bean = new UserBean("李明",20);
        binding.setUser(bean);
        //setContentView(R.layout.activity_main);
        bean.setAge(200);//改变变量,界面上的控件上的值也随之相应改变
    }

}

默认的activityonCreate函数内容是这样的

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

因为布局文件不是原先的哪种模式了,所以就要换一个setContentView函数

  ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);

这个函数顺便就返回了对应布局文件的Binding对象
通过这个对象我们就可以给xml文件中声明却未初始化的变量赋值了

UserBean bean = new UserBean("李明",20);
binding.setUser(bean);//这个函数也是自动生成的,只要在xml中声明了的variable标签,都会生成一个相应的`setXxx`函数,用于赋值

运行起来


效果图

在Fragment里面使用

随便创建一个Activity,然后在里面放一个Fragment控件,在主界面放一个按钮,跳转到这个activity
编写fragment的布局文件代码

<?xml version="1.0" encoding="utf-8"?>
<layout  xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name = "user"
            type = "com.kehao.databinding1.bean.UserBean"
            />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#F44336"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="This is a red fragment" />

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

        <!--注意:这里age是int类型,必须转化为String,否则会运行时异常-->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(user.age)}" />

    </LinearLayout>
</layout>

然后在Fragment中编写代码

public class BlankFragment extends Fragment {

    private FragmentBlankBinding binding;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding = FragmentBlankBinding.inflate(inflater);
        UserBean user = new UserBean("张三",11);
        binding.setUser(user);
        return binding.getRoot();
    }

}

关键是binding = FragmentBlankBinding.inflate(inflater);获取binding对象

效果图

在RecyclerView中使用

先创建一个Activity,里面放上RecyclerView,在主界面添加一个按钮跳转之
Activity的代码

public class RecyclerActivity extends AppCompatActivity {
    private ActivityRecyclerBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this,R.layout.activity_recycler);
        RecyclerView recyclerView = binding.recyclerview;
        MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter();
        adapter.list = new ArrayList<UserBean>();
        initList(adapter.list);
        adapter.fun = ()-> Toast.makeText(this, "you touch it", Toast.LENGTH_SHORT).show();
        recyclerView.setAdapter(adapter);
        LinearLayoutManager manager = new LinearLayoutManager(RecyclerActivity.this);
        manager.setOrientation(RecyclerView.VERTICAL);
        recyclerView.setLayoutManager(manager);
    }

    private void initList(List<UserBean> list){
        for (int i = 0 ;i<10 ;i++){
            list.add(new UserBean("李"+i,i));
        }

    }
}

其中RecyclerView recyclerView = binding.recyclerview;是因为只要在布局文件中配置了id,就可以直接获取该控件对象,其他的代码都是很常见的RecyclerView的使用代码

recyclerview里面的每一项的布局文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="com.kehao.databinding1.bean.UserBean"/>
        <import type="com.kehao.databinding1.FunInterface"/>

        <variable name="user" type="UserBean" />
        <variable name="fun" type="FunInterface" />

    </data>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:onClick="@{()->fun.toDo()}"
        >

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#F44336"
            android:text="@{user.name}" />

        <TextView
            android:id="@+id/tv_age"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#4CAF50"
            android:text="@{String.valueOf(user.age)}" />
    </LinearLayout>
</layout>

其中android:onClick="@{()->fun.toDo()},这里的fun对象是一个接口,可以通过Binding对象的set方法来传入一个实现类,通过这种配置可以很方便的设置点击事件,而不需要复杂的setOnClickListener的办法
不过,官方文档中是可以使用方法引用的,但我这里不知道为什么使用方法引用的时候会报错找不到binding类,我之前填写的是@{fun::toDo},不知道是不是方法引用是不能够多态的,而这里的方法没有实现,所以我只能使用lambda表达式了,希望知道的大佬能够告诉我
附上官方文档里的案例截图

官方案例

然后创建adapter对象

package com.kehao.databinding1.adapter;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;

import com.kehao.databinding1.FunInterface;
import com.kehao.databinding1.R;
import com.kehao.databinding1.bean.UserBean;
import com.kehao.databinding1.databinding.UseritemBinding;

import java.util.List;

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder>{
    public List<UserBean> list;
    public FunInterface fun;
    @NonNull
    @Override
    public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.useritem,parent,false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder (@NonNull MyRecyclerViewAdapter.ViewHolder holder, int position) {
        UserBean user = list.get(position);
        holder.binding.setUser(user);
        holder.binding.setFun(fun);
    }

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

    static class ViewHolder extends RecyclerView.ViewHolder{
        UseritemBinding binding;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            binding = DataBindingUtil.bind(itemView);
        }
    }

}

ViewHolder承载的就是每一项的视图,而每一个Binding对象是和布局文件相关联的,所以我们就要在ViewHolder的构造函数中,获取binding对象,并将其作为成员变量方便以后调用

 static class ViewHolder extends RecyclerView.ViewHolder{
        UseritemBinding binding;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            binding = DataBindingUtil.bind(itemView);
        }
    }

而视图和变量绑定就在

 @Override
    public void onBindViewHolder (@NonNull MyRecyclerViewAdapter.ViewHolder holder, int position) {
        UserBean user = list.get(position);
        holder.binding.setUser(user);
        holder.binding.setFun(fun);
    }

所以最后的效果就是


效果图
点击之后

还有一些更加高级的使用办法,可以参见官方文档
案例代码我放到github上了:https://github.com/chenkehao1998/databinding

上一篇下一篇

猜你喜欢

热点阅读