DataBinding入门介绍

本文将介绍以下databinding的基本使用方式,主要包括数据的绑定,事件的监听,自定义监听方法等

介绍

DataBinding 是谷歌官方发布的一个框架,顾名思义即为数据绑定,是 MVVM 模式在 Android 上的一种实现,用于降低布局和逻辑的耦合性,使代码逻辑更加清晰。MVVM 相对于 MVP,其实就是将 Presenter 层替换成了 ViewModel 层。DataBinding 能够省去我们一直以来的 findViewById() 步骤,大量减少 Activity 内的代码,数据能够单向或双向绑定到 layout 文件中,有助于防止内存泄漏,而且能自动进行空检测以避免空指针异常

一、使用

1、在 app module 的 build.gradle 中添加如下代码:

android {
    dataBinding {
        enabled = true
    }
}

2、xml布局中生成 DataBinding 需要的布局规则
在布局的根目录快捷键Alt+Enter,点击 “Convert to data binding layout”即可生成如下符合规则的代码




    

    

    

        

我们知道使用当前的button控件,通常在activity中都是通过findViewById的方式,这样代码就会显得特别的臃肿。
databingding和kotlin一样,最大的不一样就是可以直接通过id找到控件。
上面的例子我们已经生成了一个符合DataBinding规则的一个布局文件,那么此时系统就会默认帮我们生成了一个viewBinding的类。

public class TestActivity extends AppCompatActivity {
    private AcitivityTestBinding mBinding;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        int layoutId = R.layout.acitivity_test;
        mBinding = DataBindingUtil.setContentView(this, layoutId);
        mBinding.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });

    }
}

可以看到我们定义了一个Binding,他的命名规则是 布局文件名字+Binding 。例如activity_test.xml对应的就是ActivityTestBinding 。 可以看到使用控件直接调用mBinding.button

事件监听

我们知道事件监听包括点击、长按等,在activity中代码通常需要写上一大段的回调,而DataBinding却为我们提供了很好的方式,网上有很多文章关于事件监听的,但是经过测试很多都会出错或者不能用。下面我们好好总结下。
首先定义的方法和事件匿名内部类中定义的返回类型必须相同,比如点击长按事件

 mBinding.button.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                return false;
            }
        });

对于DataBinding的事件监听的写法我们可以写一个内部类,然后定义类中的方法。针对上面的长按事件首先根据规则定义方法

 public class OnEventListener{
        public boolean onLongClick(){
            Log.d(TAG, "onLongClick: ");
            return true;
        }
    }

对应的xml布局文件中的定义




    

        
    

    

        

注意必须引入OnEventListener。
事件监听有了,接着记得绑定上内部类。因为我们在布局中生命了listener。所以databinding就会自动生成一个设置的方法

  mBinding.setListener(new OnEventListener());

这句话就相当于原始绑定监听事件的代码,不同的是它可以同时把所有内部类中定义的方法都绑定,比起源生代码又减少了一部分。
那么有人会问,onLongClick(View view)参数列表中的view呢? 如果我需要使用呢?或者我想另外添加一个参数又要怎么定义呢?
其实事件绑定本人总结了三种的定义的方式:第一种不带任何参数(参考以上写法)、第二种带上原始的参数、第三种附加自定义参数

对于第一种写法请参考以上代码
第二种带原始参数:

public class OnEventListener{
        public boolean onLongClick(View view){
            Log.d(TAG, "onLongClick: ");
            return true;
        }
    }

对应的xml布局

 

第三种写法带上自定义参数:
分为两种:
1、直接添加额外的参数

  public class OnEventListener {
        public boolean onLongClick(String url) {
            Log.d(TAG, "onLongClick: "+url);
            return true;
        }
    }

对应的xml布局

 

2、添加原始参数+自定义参数

  public class OnEventListener {
        public boolean onLongClick(View view,String url) {
            Log.d(TAG, "onLongClick: "+view.getId()+url);
            return true;
        }
    }

对应的xml布局


        

其他的事件监听只要遵循以上的规则即可,例如checkbox的事件监听

  public void onCheck(CompoundButton buttonView, boolean isChecked) {
            Log.d(TAG, "onCheck: " + isChecked);
        }

当然写法可能有很多种例如网上还出现其他的写法可以运行,但是以上写法基本满足我们日常的开发。

数据绑定

通常情况下想要设置一个TextView的值需要写类似的代码 tv.setText("content");
DataBinding提供了数据和布局绑定的功能。例如我们可以申明一个ViewModel,以LoginViewModel作为例子




    

        
        
    

    

        

可以看到 TextView的值已经绑定了model.respondData,一旦定义了一个变量相应的DataBinding就可以设置属性,例如我们设置了listener,DataBinding就有了setListener,定义了一个model它就有了setModel的方法。

public class TestActivity extends AppCompatActivity {
    private static final String TAG = TestActivity.class.getSimpleName();

    private AcitivityTestBinding mBinding;
    private LoginViewModel loginViewModel ;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        int layoutId = R.layout.acitivity_test;
        mBinding = DataBindingUtil.setContentView(this, layoutId);
        mBinding.setListener(new OnEventListener());
        //这句话不设置则无法监听
        mBinding.setLifecycleOwner(this);
        loginViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
        mBinding.setModel(loginViewModel);

    }


    public class OnEventListener {
        public boolean onLongClick(View view,String url) {
            Log.d(TAG, "onLongClick: "+view.getId()+url);
            return true;
        }

        public void onLoginClick(){
            loginViewModel.doLogin("xxx","xxx");
        }
    }
}

一旦TextView绑定了model中respondData的值,那么TextView就会和该值绑定双向绑定,一方改变另一方必然改变。
当调用doLogin接口,respondData的值会被设置那么TextView显示的值也会被改变。

//LoginViewModel.class (doLogin)

 public void doLogin(final String userName, final String paw) {
        Observable observable = Observable.create(
                new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter) {
                Log.d("TAG", "subscribe:" + Thread.currentThread().getName());
                LoginRespondBean login = ControlApi.getInstance().login(userName, paw);
                emitter.onNext(login);
            }
        });
        //切换到io异步线程执行耗时操作,并将结果返回到主线程
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer() {
                    @Override
                    public void accept(LoginRespondBean loginRespondBean) {
                        Log.d("TAG", "accept:" + Thread.currentThread().getName());
                        respondData.setValue(loginRespondBean);
                    }
                });

    }

这里我们使用了LiveData配合DataBinding的使用。完整的代码如下

public class LoginViewModel extends ViewModel {
    public MutableLiveData respondData = new MutableLiveData<>();
    public MutableLiveData registerData = new MutableLiveData<>();

    /**
     * 需要关心结果
     *
     * @param userName
     * @param paw
     */

    public void doLogin(final String userName, final String paw) {
        Observable observable = Observable.create(
                new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter) {
                Log.d("TAG", "subscribe:" + Thread.currentThread().getName());
                LoginRespondBean login = ControlApi.getInstance().login(userName, paw);
                emitter.onNext(login);
            }
        });
        //切换到io异步线程执行耗时操作,并将结果返回到主线程
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer() {
                    @Override
                    public void accept(LoginRespondBean loginRespondBean) {
                        Log.d("TAG", "accept:" + Thread.currentThread().getName());
                        respondData.setValue(loginRespondBean);
                    }
                });

    }
}

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


自定义参数绑定:BindingAdapter

最常见的例子就是一个ImageView需要设置图片
一般的是写法是 获取到图片的url后借助Glide设置编写java代码。 同样的DataBinding也提供了一种自定义参数绑定的方式BindingAdapter
同样在ViewModel中定义一个方法:

public class DriverViewModel extends ViewModel {
    @BindingAdapter({"imageUrl"})
    public static void loadImage(ImageView imageView, String url){
        Glide.with(imageView.getContext()).load(url)
                .placeholder(R.mipmap.ic_launcher)
                .into(imageView);
    }

}

"imageUrl"表示xml控件中设置的属性名
参数列表中第一个必须是View或者子View的类型,第二个参数是自定义参数。

   

布局中设置了一个url,属于String类型。不管引入什么对象类型的变量都需要申明,

  

        

        

        
    

同样的道理我们的DataBinding就多了一个setUrl的方法,只要将正常的url地址设置进去就可以完成图片加载了。
未完待续...

你可能感兴趣的:(DataBinding入门介绍)