美文网首页
Android DataBinding初探

Android DataBinding初探

作者: KeHaoo | 来源:发表于2020-04-08 20:35 被阅读0次

    官方的文档有一点晦涩难读,如果直接看案例也很头疼
    今天算是对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

    相关文章

      网友评论

          本文标题:Android DataBinding初探

          本文链接:https://www.haomeiwen.com/subject/uofxmhtx.html