DataBinding使用介绍

DataBinding简介

dataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,利用该库可以实现在页面组件中直接绑定应用程序的数据源。

DataBinding的作用

dataBinding翻译后叫数据绑定,它的主要作用是与UI界面绑定,通过dataBinding获取页面数据与修改页面数据。同时dataBinding还具有观察性,数据模型或者UI界面数据改变之后,它可以同步数据。

为什么使用DataBinding

由于Android开发语言的限制,在数据加载问题上设计了MVC、MVP架构不是代码臃肿就是方法满天飞,导致代码维护难度很大,开发者也很难准确的使用这些架构,还有就是这些架构从根本上来讲,还是没有解决数据与页面的绑定关系。dataBinding的就是为了解决这样的问题而出现,只要创建好对应实体类或者方法,即可轻松将数据绑定到UI上,UI随着数据的改变自动更新,反之亦然,大大的减少了代码量。

DataBinding的使用主要有以下几点

配置gradle

这也是最基础的一步,在module中的build.geadle中配置

android {
    ...
   buildFeatures {
        dataBinding true
   }
}

配置Layout

基础配置



    
    

    

        

    

使用layout标签和data标签,其中layout标签需要包裹data标签与UI布局,如上述XML代码

如果您希望在生成绑定类时忽略某个布局文件,请将 tools:viewBindingIgnore="true" 属性添加到相应布局文件的根视图中:

       
     ...    

activity关联layout布局

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding dataBinding;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        dataBinding.textView.setText("");
        dataBinding.textView.getText();
    }
}

DataBinding是通过DataBindingUtil下的setContentView(Activity activity,int layoutId)方法与layout布局关联,返回一个泛型( T)内部规则Activity+Activity类名(去掉Activity)+Binding,例如MainActivity返回的是ActivityMainBinding。返回的泛型也可以通过layout中的data标签中的class属性(注意这里自定义class名称一定要与页面关联,个人不建议自定义)。

DataBinding与组件关联是通过组件id进行关联的例如dataBinding.textView,内部规则采用驼峰式命名风格转换layout中的组件id。

DataBinding与Fragment关联是通过inflate(LayoutInflater inflater, int layoutId, ViewGroup parent, boolean attachToParent)方法绑定的,与activity关联大同小异,有兴趣可以自己研究一下。

上述部分是DataBinding的基础使用部分,有这些我们就可以实现UI界面与Activity或者Fragment的绑定,下面主要说的是数据双向绑定。

数据绑定

data节点下标签使用




    
        

        
    

    

        


    

layout布局中data节点是存放数据。data 中的 variable 标签为变量,类似于我们定义了一个变量,name 为变量名,type 为变量全限定类型名,包括包名。import标签是用来导入包名\类名,还可以通过alias属性设置别名。布局中通过 @{} 来引用这个变量的值,{} 中可以是任意 Java 表达式,但不推荐使用过多的代码。

绑定普通数据

    @Override
    protected void initView() {
        dataBinding.setContents("演示DataBinding数据绑定");
        handler.removeMessages(0);
        handler.sendEmptyMessageDelayed(0,2000);
    }

    Handler handler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            sign++;
            dataBinding.setContents("演示DataBinding数据绑定: " + sign);
            handler.removeMessages(0);
            handler.sendEmptyMessageDelayed(0,2000);
            Log.d(TAG,dataBinding.getContents());
        }
    };

DataBinding 可以绑定普通数据对象(非 Observable/LiveData),例如上述例子中绑定了一个 String 类型的数据。绑定普通数据我们只需要按照上述的代码设置即可。

绑定可观察数据

绑定可观察数据意味着当数据变化时 UI 会跟着一起变化,绑定可观察数据有三种方式:fields、 collections和 objects.

fields变量绑定(单个变量)




    
        

        
    

    

        

    
public class MainActivity extends BaseActivity {

    private static final String TAG = MainActivity.class.getName();

    ObservableField inputs = new ObservableField<>("演示ObservableField");

    @Override
    protected void initView() {
        dataBinding.setInput(inputs);
    }

}

fields变量绑定主要是引用带有泛型参数的ObservableField来创建,其中泛型是数据类型。

对于基本类型和 Parcelable 我们可以直接使用对应的包装类:

  • ObservableBoolean

  • ObservableByte

  • ObservableChar

  • ObservableShort

  • ObservableInt

  • ObservableLong

  • ObservableFloat

  • ObservableDouble

  • ObservableParcelable

collections数据绑定(集合数据)




    
        

        

        

        
    

    

        

        

    
public class MainActivity extends BaseActivity {

    private static final String TAG = MainActivity.class.getName();

    ObservableMap maps  = new ObservableArrayMap<>();
    ObservableList lists = new ObservableArrayList<>();
    int listSign = 0;
    boolean isName = true;


    Handler handler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1:
                    if (isName){
                        isName = false;
                        dataBinding.setMapKey("name");
                    }else{
                        isName = true;
                        dataBinding.setMapKey("age");
                    }
                    handler.removeMessages(1);
                    handler.sendEmptyMessageDelayed(1, 2000);
                    break;
                case 2:
                    if (listSign<5){
                        dataBinding.setListSubscript(listSign);
                        listSign++;
                    }else{
                        listSign = 0;
                        dataBinding.setListSubscript(listSign);
                    }
                    handler.removeMessages(2);
                    handler.sendEmptyMessageDelayed(2, 2000);
                    break;
            }

        }
    };

    @Override
    protected void data() {
        maps.clear();
        maps.put("name","Map集合演示:1");
        maps.put("age","Map集合演示:2");
        dataBinding.setMap(maps);
        lists.clear();
        for (int i = 0; i < 5; i++) {
            lists.add("list集合数据演示:" + i);
        }
        dataBinding.setList(lists);
        handler.removeMessages(1);
        handler.sendEmptyMessageDelayed(1, 2000);
        handler.removeMessages(2);
        handler.sendEmptyMessageDelayed(2, 2000);
    }
}

对于集合而言,List是通过下标去取值的,而Map是通过key取value,我通过定义两个变量listSubscript和mapKey,通过代码修改这两个变量来改变取值。

对于集合提供的包装类

  • ObservableArrayList

  • ObservableArrayMap

objects数据绑定(对象)




    
        
    

    
        

        

    
public class UserBean extends BaseObservable {


    private String name;
    private int age;


    public UserBean(String name, int age) {
        this.name = name;
        this.age = age;
        notifyPropertyChanged(BR.user);
    }

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

    @Bindable
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        notifyPropertyChanged(BR.age);
    }
}
    Handler handler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 3:
                    age++;
                    UserBean userBean = new UserBean("tao",age);
                    dataBinding.setUser(userBean);

                    handler.removeMessages(3);
                    handler.sendEmptyMessageDelayed(3, 2000);
                    break;
            }
        }
    };

    @Override
    protected void data() {
        handler.removeMessages(3);
        handler.sendEmptyMessageDelayed(3, 2000);

    }

对应对象而言必须BaseObservable或者Observable,BaseObservable相对于Observable比较完善,使用更简单,get方法需要加注解@Bindable,set方法使用notifyPropertyChanged通知对于变量更新。

Observable 接口具有添加和移除监听器的机制,但何时发送通知必须由您决定。为便于开发,数据绑定库提供了用于实现监听器注册机制的 BaseObservable 类。实现 BaseObservable 的数据类负责在属性更改时发出通知。具体操作过程是向 getter 分配 Bindable 注释,然后在 setter 中调用 notifyPropertyChanged() 方法

双向绑定




    
        

    

    
        

        
    

双向绑定直接在@{}中间加上@={}

事件绑定




    
        

    

    

        
    @Override
    protected void initView() {
        dataBinding.setClickHandler(clickHandler);
    }

    ClickHandler clickHandler = new ClickHandler(){
        @Override
        public void onSubmit(View v) {
            Log.d(TAG, "onSubmit:");
        }

        @Override
        public void onConfirm(View v) {
            Log.d(TAG, "onConfirm:");
        }
    };
    public interface ClickHandler {
         void onSubmit(View v);

         void onConfirm(View v);
    }

事件绑定个人认为有点本末倒置,没有那么方便好用,不过写到这里了,还是说一下,事件绑定与数据绑定variable标签内容与对象绑定差不多,都需要导入一个类(内部类或者回调接口),在写方法的时候需要注意一下带个参数view或者在组件中使用(View)->clickHandler::onConfirm,个人习惯卸载方法参数中,其中“::”也可以换成"."方法名,还有就是不管是方法还是类都需要使用public修饰一下。

BindingAdapter(自定义参数绑定

目前已经支持的双向绑定的参数列表如下:

DataBinding使用介绍_第1张图片

除了上述的参数外,我们也可以使用 BindingAdapter 创建自定义参数。




    

        
 
        

        

    

    

        

        

    
    @Override
    protected void data() {
        dataBinding.setNetworkPictures("https://x0.ifengimg.com/ucms/2022_10/8A28619D49C8DE5999F84E9101E304F4F9DA73E1_size127_w1008_h435.jpg");
        dataBinding.setLocalPictures(R.mipmap.ic_launcher);
    }


    @BindingAdapter("image")
    public static void setImage(ImageView v, String url) {
        if (!TextUtils.isEmpty(url)) {
            Picasso.get().load(url).into(v);
        } else {
            v.setBackgroundColor(Color.GRAY);
        }
    }

    @BindingAdapter(value = {"netWorkImage","defaultLocalImage"},requireAll = false)
    public static void setImage(ImageView v, String url,int rid){
        if (!TextUtils.isEmpty(url)) {
            Picasso.get().load(url).placeholder(R.mipmap.ic_launcher).into(v);
        } else {
            v.setImageResource(rid);
        }
    }

layout中的image、defaultLocalImage与netWorkImage都是通过BindingAdapter自定义的,需要注意的是定义的方法必须是静态方法哦,关于URL的传入就和正常的数据绑定一样即可。

LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

如果观察者(由Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。

您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 activity 和 fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 activity 和 fragment 的生命周期被销毁时,系统会立即退订它们)。

如需详细了解如何使用 LiveData,请参阅使用 LiveData 对象。

LiveData对象在使用时,需要注意一下LiveData不能直接被改变,需要改变LiveData时请使用MutableLiveData。

 //点击事件
    ClickHandler mClickHandler = new ClickHandler(){
        @Override
        public void onSubmit(View v) {
            Log.d(TAG, "onSubmit: ");
            liveData.setValue("更新演示数据");
        }

        @Override
        public void onConfirm(View v) {
            Log.d(TAG, "onConfirm: ");
        }
    };

    MutableLiveData  liveData = new MutableLiveData<>("演示");

    public void LiveDateMonitor(){
        Observer liveDataObserver  = s -> {
            dataBinding.setContents(s);
        };
        liveData.observe(this,liveDataObserver);
    }

总结

针对上述描述,以满足databinding的初步使用,demo关于LiveData部分尚未完善,暂不上传(有需要的可以留言),由于工作原因,暂时先更新这么多,若是有人针对liveData有更好的例子,大家可以推荐一下,我这边也会找时间更新这部分。

有兴趣的也可以去官网瞅瞅:DataBinding ViewBinding

DataBinding使用介绍_第2张图片

你可能感兴趣的:(学习,Android,android)