上一篇介绍了mvp的实现思路,这里介绍android原生自带的数据绑定框架的使用。对于的官方工程也是放在mvp简介的介绍页面里的,
对应的官方Data Binding示例地址为:https://github.com/googlesamples/android-architecture/tree/todo-databinding/
也可以查看官方关于Data Binding 库的说明:http://developer.android.com/tools/data-binding/guide.html#data_objects
安卓的实现一个界面,正常的做法是新建一个Activity类,新建一个layout文件,在Activity的setContentView(R.layout.xxxxx);把Activity类与layout布局绑定,然后使用findViewById(R.id.xxxx)找到指定控件,然后对控件做相应的操作,对于列表控件显示也是大概相同的流程,都是View view = LayoutInflater.from(Context()).inflate(R.layout.xxx, viewGroup, false);找到父容器控件后再View.findViewById(R.id.xxx)找到具体的控件,对其进行相应的设置。
Data Binding 库能实现的功能是在layout布局文件定义时,就指定了数据与控件的绑定和界面事件的处理。省去了必须findViewById的麻烦,以及更好的做到数据与界面的分离。
1.控件与数据的绑定,在layout里指定控件的一些属性怎样与指定的数据绑定
android:text="@{task.title}"
代替以往的。((EditText)findViewById(R.id.add_task_title)).setText(task.getTitle());
<EditText android:id="@+id/add_task_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/title_hint" android:text="@{task.title}" android:singleLine="true" android:textAppearance="@style/TextAppearance.AppCompat.Title" />
android:visibility="@{stats.showStatus ? View.VISIBLE : View.GONE}"
代替以往的findViewById(R.id.add_task_title).setVisibility(task.showStatus?View.VISIBLE: View.GONE);
<TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="@{stats.status}" android:textAppearance="?android:attr/textAppearanceMedium" android:visibility="@{stats.showStatus ? View.VISIBLE : View.GONE}" />
android:background="@{task.isCompleted?@drawable/list_completed_touch_feedback: @drawable/touch_feedback}"
代替以往的 View.setBackgroundResource(task.isCompleted?R.drawable.xxx: R.drawable/xx);
<LinearLayout android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:background="@{task.isCompleted ? @drawable/list_completed_touch_feedback : @drawable/touch_feedback}" android:orientation="horizontal" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingBottom="@dimen/list_item_padding" android:paddingTop="@dimen/list_item_padding" android:onClick="@{() -> actionHandler.taskClicked(task)}">
2.控件与方法的绑定,在layout里指定控件的一些点击接口或其他回调接口怎样与对应的方法绑定。
android:onClick="@{() -> actionHandler.taskClicked(task)}"
代替View.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
<LinearLayout android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:background="@{task.isCompleted ? @drawable/list_completed_touch_feedback : @drawable/touch_feedback}" android:orientation="horizontal" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingBottom="@dimen/list_item_padding" android:paddingTop="@dimen/list_item_padding" android:onClick="@{() -> actionHandler.taskClicked(task)}">
如何使用Data Binding 库
1.开发环境:
compileSdkVersion 25
buildToolsVersion "25.0.2"
classpath 'com.android.tools.build:gradle:2.3.0'
并不需要根项目声明apt插件,
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
也不需要在模块里
apply plugin: 'com.neenbedankt.android-apt'
只需要在用到的模块下加入下面语句。
dataBinding { enabled = true }
2.1用于与界面绑定数据的java
新建Java类,并继承 android.databinding.BaseObservable,把需要在layout布局里引用的方法,加上@Bindable注解或@BindingAdapter, 使用@Bindable注解过的方法可以直接使用在xml布局里,如下面定义的getName()方法,可以在layout里这样使用
android:text='@{"name:"+company.getName()}'
public class Company extends BaseObservable{ ......省略若干代码 @BindingAdapter({"bind:imageUrl", "bind:error"}) public static void setIcon(ImageView view, String url, Drawable error) { Glide.with(view.getContext()).load(url).error(error).into(view); } @Bindable public String getName() { return name; } ......省略若干代码 }
如果layout里需要用到一些工具类里的静态方法,不需要继承BaseObservable,也不需要在方法前增加注解。
public class DateUtil{ ......省略若干代码 public static String getTime(long time) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); return sdf.format(time); } ......省略若干代码 }
2.2 用于与控件绑定事件的类,不需要使用注解。像普通的java类一样定义即可。
public class ActionHandler { private Context mContext; public ActionHandler(Context context) { this.mContext = context; } public void showTextDialog(String text) { new AlertDialog.Builder(mContext).setTitle("detail") .setMessage(text).create().show(); } }
在layout里即可调用:android:onClick="@{(tv)->actionHandler.showTextDialog(company.toString())}"
3.定义layout布局
不使用Data Binding 库的layout布局如下。
xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.databindtest.MainActivity">
......省略若干代码
LinearLayout>
使用Data Binding库需要以layout为根标签,并加入一个data子标签,
data标签里常用到的有variable和import标签,
variable标签引入的是一个需要在java代码里动态设置的对象,type字段是Java类的导入,相当于代码里的import android.databinding.BaseObservable;
name字段相当于变量名称。
当data标签里有如下的一段代码时,
<variable name="company" type="com.example.databindtest.Company" />
当自动生成的Data Binding对象会生成一个setCompany(com.example.databindtest.Company c)的方法
import 标签一般是声明需要引用一些工具类里的里的静态方法。
和一些用到的类型,如果app:error="@{@drawable/ic_launcher'}" 就需要先声明Drawable。
无论是绑定数据还是事件方法,都是找到对象然后调用相应的get方法或事件方法。
xml version="1.0" encoding="utf-8"?> <layout xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="company" type="com.example.databindtest.Company" /> <variable name="actionHandler" type="com.example.databindtest.ActionHandler" /> <import type="android.graphics.drawable.Drawable" /> <import type="com.example.databindtest.DateUtil" /> data> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/company_item_root_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/cardview_dark_background" android:padding="8dp"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.CardView android:id="@+id/cv_wrap" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp"> <ImageView android:id="@+id/iv_icon" android:layout_width="80dp" android:layout_height="80dp" android:minHeight="80dp" android:minWidth="80dp" android:layout_centerVertical="true" android:onClick="@{(tv) -> actionHandler.showImageDialog(company.getIcon())}" app:error="@{@drawable/ic_launcher'}" app:imageUrl="@{company.getIcon()}" /> android.support.v7.widget.CardView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginTop="8dp" android:layout_toRightOf="@id/cv_wrap" android:orientation="vertical"> LinearLayout> RelativeLayout> android.support.v7.widget.CardView> FrameLayout> layout>
做完上面的工作后,已经准备好了数据实体对象和layout布局,如果这时候使用了android studio的Build->Make Module 'xxx'的编译某个模块的功能,如果没有编译出错,可以看到在相应的临时编译生成了对应的xxxBinding文件,如下图所示
只需要在Activity里简单的调用几句,就可以实现数据自动填充到View,并且绑定控件的事件处理方法。
调用 Binding.setCompany(mCompany);会自动把数据填充到View上。
package com.example.databindtest; import android.content.Context; import android.databinding.DataBindingUtil; import android.support.annotation.Nullable; import android.support.v4.app.DialogFragment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import com.example.databindtest.databinding.CompanyItemLayoutBinding; import java.util.List; public class MainActivity extends AppCompatActivity { private Company mCompany; CompanyItemLayoutBinding mBinding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBinding = DataBindingUtil.bind(findViewById(R.id.company_item_root_layout)); mCompany = Company.getCompanyList().get(0); mBinding.setActionHandler(new ActionHandler(this)); mBinding.setCompany(mCompany); initView(); } //......省略若干代码 public void setting(View view) { mCompany.setIcon(((EditText)findViewById(R.id.et_company_icon_path)).getText().toString()); mCompany.setName(((EditText)findViewById(R.id.et_company_name)).getText().toString()); mCompany.setInfo(((EditText)findViewById(R.id.et_company_info)).getText().toString()); mBinding.setCompany(mCompany); } //......省略若干代码 }
完整代码请查看
https://git.oschina.net/null_979_4294/MVP-DataBinding1