开源数据绑定框架android-databinding与google databinding对比
0,前言:
google databinding: 指google 2015 io大会后出的数据绑定框架.
android-databinding: 指 heaven7所出的android开源数据绑定框架。
github地址: https://github.com/LightSun/android-databinding
1, 先说下 数据绑定 (思想都是一样的,类似javaweb数据绑定)。
优点:
1) , 大量减少 findViewById,setBackgroundColor, setImageBitmap,setText,setTextColor 等方法
的调用。
2), 减轻Activity的代码负担,使得使用者不用复杂的设计模式即可使得代码变得清晰,可读性也很强,
易于维护。
缺点:
一旦数据绑定相关的方法名或者字段名修改后,数据绑定配置文件也得跟着修改。
多牺牲一些内存。
2, 对比google官方的databinding-library
【google databinding 优点】:
1), 相关的部分代码自动生成(as支持)。 —-> 本框架目前只有简单的as插件
2), 不需要在layout中定义id(但是由于业务的复杂性,很多地方仍然需要定义id).
(本框架放置在res/raw目录下。)
3), 更加丰富的Java表达式的支持。(本框架支持相对弱点,但是足够使用)
google: 所有运算符及嵌套均支持,支持所有java 表达式(除开this,super,new,Explicit generic
invocation)。支持android资源引用..
本框架:java字段、方法和数组的调用(可嵌套)。以及1次3元运算符(不支持其他运算符,
如果你非要用建议以静态方法的方式调用 )。亦支持android资源引用.
4), 相对清晰轻量的架构 。
google databinding的原代码见:
sdk\sources\android-23\android\databinding包。
【Google databinding 缺点】:
1), 数据绑定的配置在对应的layout文件中,会影响布局文件的可读性。尤其的布局复杂之后。
(大家都懂的).
2), 图片边框/圆角/placeholder等不直接支持。
3), 需要手动写RecyclerView等的adapter
【本框架具有,google databinding不具有的】:
1),一般的,不需要你写 listView/GridView/RecyclerView的
adapter.(框架内部自动帮你完成的)
2)更加丰富的事件绑定支持,事件绑定传递自定义参数(包括adapter item事件 绑定).
什么意思呢? Eg:….
3), 图片圆角,边框,圆形等的支持。
3, 具体使用对比(代码)
(1), 基本绑定.
google databinding:
public class Student {
private String name;
private String addr;
public Student() {
}
public Student(String name, String addr) {
this.name = name;
this.addr = addr;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddr() {
return this.addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
//布局文件如下
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="stu"
type="org.loader.androiddatabinding.Student" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{stu.name}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{stu.addr}"/>
</LinearLayout>
</layout>
//调用代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding binding = DataBindingUtil.setContentView(
this,R.layout.activity_main);
binding.setStu(new Student("loader", "干锅排骨"));
}
}
Android-databinding :
//布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity"
android:orientation="vertical"
>
<Button
android:id="@+id/bt"
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:padding="5dp"
/>
</LinearLayout>
//数据绑定配置文件
<DataBinding
xmlns = "http://schemas.android.com/heaven7/android-databinding/1"
version="1.0"
>
<data>
<variable name="user" classname="com.heaven7.databinding.demo.bean.User"
type="bean"/>
<variable name="mainHanlder"
classname="com.heaven7.databinding.demo.callback.MainEventHandler"
type="callback"/>
<import classname="android.view.View" alias="View"/>
</data>
// 绑定文本,文本颜色,背景颜色
<bind id="bt">
<property name="text" referVariable="user" >@{user.username}</property>
<property name="textColor" referVariable="user" >user.male ? {@color/red}
:{@color/random}</property>
<property name="backgroundColor" referVariable="user" >#00ff00</property>
</bind>
</DataBinding>
//调用示例代码:
DataBinder.getDataBinder(this, R.raw.db_main,false)
.bind(R.id.bt, true, mUser = new User("heaven7", false));
2), 事件绑定:
google databinding:
//布局文件
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="org.loader.app3.EventHandlers" />
<variable
name="handlers"
type="EventHandlers" />
</data>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CLICK ME"
android:onClick="@{handlers.handleClick}"/>
</LinearLayout>
</layout>
// 事件处理类
public class EventHandlers {
public void handleClick(View view) {
Toast.makeText(view.getContext(), "you clicked the view",
Toast.LENGTH_LONG).show();
}
}
android-databinding:
//布局文件
<Button
android:id="@+id/bt0"
android:text="@string/change_data_by_handler"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:padding="5dp"
/>
//数据绑定配置文件
<DataBinding
xmlns = "http://schemas.android.com/heaven7/android-databinding/1"
version="1.0"
>
<data>
<variable name="user" classname="com.heaven7.databinding.demo.bean.User"
type="bean"/>
<variable name="mainHanlder"
classname="com.heaven7.databinding.demo.callback.MainEventHandler"
type="callback"/>
<import classname="android.view.View" alias="View"/>
</data>
//**绑定的点击事件和长按点击事件**
<bind id="bt0">
<property name="onClick" referVariable="user,mainHanlder" >
mainHanlder.onClickChangeUsername(user) </property>
<property name="onLongClick" referVariable="user,mainHanlder" >
mainHanlder.onLongClickChangeUsername(user)</property>
</bind>
</DataBinding>
//调用相关代码
@DatabindingClass
public class MainEventHandler extends EventContext{
public MainEventHandler(IDataBinder binder) {
super(binder);
}
@DatabindingMethod
public void onClickChangeUsername(View v,User user){
Util.changeUserName(user,"by_MainEventHandler_OnClick");
//change male
user.setMale(!user.isMale());
getDataBinder().notifyDataSetChanged(R.id.bt);
}
@DatabindingMethod
public void onLongClickChangeUsername(View v,User user){
Toast t = Toast.makeText(v.getContext(),
"------------ onLongClick ---------", Toast.LENGTH_SHORT);
t.setGravity(Gravity.CENTER, 0, 0);
t.show();
Util.changeUserName(user, "by_MainEventHandler_OnLongClick");
getDataBinder().notifyDataSetChanged(R.id.bt, PropertyNames.TEXT);
}
}
DataBinder.getDataBinder(this,R.raw.db_main,false))
.bind(R.id.bt0, false, mUser,new MainEventHandler(mDataBinder))
3),图片的绑定
Google databinding:
//布局文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<data class=".Custom">
<variable
name="imageUrl"
type="String" />
</data>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:image="@{imageUrl}"/>
</layout>
//调用相关代码
public class Utils {
@BindingAdapter({"bind:image"})
public static void imageLoader(ImageView imageView, String url) {
ImageLoaderUtils.getInstance().displayImage(url,
);
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
org.loader.app8.Custom binding = DataBindingUtil.setContentView(this,
R.layout.activity_main);
binding.setImageUrl("http://images.youkuaiyun.com/20150810/Blog-
Image%E5%89%AF%E6%9C%AC.jpg");
}
}
android-databinding:
//布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.android.volley.extra.ExpandNetworkImageView
android:id="@+id/eniv2"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
/>
</LinearLayout>
//数据绑定配置文件
<DataBinding
xmlns = "http://schemas.android.com/heaven7/android-databinding/1"
version="1.0"
>
<data>
<variable name="imageParam" classname="com.heaven7.databinding.demo.samples.RoundImageBindTest$ImageParam"
type="bean"/>
<variable name="eventHandler" classname="com.heaven7.databinding.demo.samples.RoundImageBindTest$ClickHandler"
type="callback"/>
<import classname="com.heaven7.databinding.demo.test.Test" alias="Test"/>
</data>
//点击事件, 图片url,圆角,边框,默认图,错误图的配置
<bind id="eniv2">
<property name="onClick" referVariable="eventHandler" >
eventHandler.onClickImage()</property>
<imageProperty type="round" referVariable="imageParam">
<roundSize>{@dimen/corner_size}</roundSize>
<borderWidth>5dp</borderWidth>
<borderColor>#ff0000</borderColor>
<url>imageParam.link</url>
<default>{@drawable/ic_default}</default>
<errorResId>R.drawable.ic_error</errorResId>
</imageProperty>
</bind>
</DataBinding>
//调用相关代码
public class RoundImageBindTest extends BaseActivity {
@Override
protected int getBindRawId() {
return R.raw.db_round_image_test;
}
@Override
protected int getlayoutId() {
return R.layout.activity_round_image_test;
}
@Override
protected void onFinalInit(Bundle savedInstanceState) {
}
@Override
protected void doBind() {
mDataBinder.bind(R.id.eniv2, false, new ImageParam(
Test.URLS[1]),new ClickHandler(getToaster()) );
}
public static class ImageParam{
float roundSize;
@DatabindingField
String url;
String link;
public ImageParam(float roundSize, String url) {
this.roundSize = roundSize;
this.url = url;
}
public ImageParam(String link) {
this.link = link;
}
}
public static class ClickHandler{
private final Toaster mToaster;
public ClickHandler(Toaster mToaster) {
this.mToaster = mToaster;
}
public void onClickImage(View v){
mToaster.show("--------- onClickImage ------------");
}
}
}
4), ListView / RecyclerView / GridView adapter数据的绑定
Google databinding:
//item 布局文件
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="stu"
type="org.loader.app6.Student" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{stu.name}"
android:layout_alignParentLeft="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(stu.age)}"
android:layout_alignParentRight="true"/>
</RelativeLayout>
</layout>
//adapter代码
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<Student> mData = new ArrayList<>();
private MyAdapter(ArrayList<Student> data) {
mData.addAll(data);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater
.from(viewGroup.getContext()), R.layout.item, viewGroup, false);
ViewHolder holder = new ViewHolder(binding.getRoot());
holder.setBinding(binding);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
viewHolder.getBinding().setVariable(org.loader.app6.BR.stu,
mData.get(i));
viewHolder.getBinding().executePendingBindings();
}
@Override
public int getItemCount() {
return mData.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
private ViewDataBinding binding;
public ViewHolder(View itemView) {
super(itemView);
}
public void setBinding(ViewDataBinding binding) {
this.binding = binding;
}
public ViewDataBinding getBinding() {
return this.binding;
}
}
}
//调用主要代码
private RecyclerView mRecyclerView;
private ArrayList<Student> mData = new ArrayList<Student>() {
{
for (int i=0;i<10;i++) add(new Student("loader" + i, 18 + i));
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false));
mRecyclerView.setAdapter(new MyAdapter(mData));
}
android-databinding:
//item布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.android.volley.extra.ExpandNetworkImageView
android:id="@+id/eniv"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
/>
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:padding="10dp"
/>
</LinearLayout>
//数据绑定配置文件
?xml version="1.0" encoding="utf-8"?>
<DataBinding
xmlns = "http://schemas.android.com/heaven7/android-databinding/1"
version="1.0"
>
<data>
<variable name="imageInfo"
classname="com.heaven7.databinding.demo.bean.ImageInfo" type="bean"/>
<variable name="itemHandler" classname="com.heaven7.databinding.demo.samples.ListViewBindAdapterTest$ItemHandler"
type="callback"/>
</data>
<bindAdapter id="rv" referVariable="imageInfo" selectMode="1">
<item layout="item_image" referVariable="itemHandler">
<property name="onClick" >itemHandler.onItemClick()</property>
<bind id="tv">
<property name="text" >imageInfo.desc</property>
<property name="textColor" >imageInfo.isSelected() ?
{@color/red} : {@color/random}</property>
<property name="onClick" >itemHandler.onTextClick()</property>
</bind>
<bind id="eniv">
<property name="img_url" >imageInfo.url</property>
</bind>
</item>
</bindAdapter>
</DataBinding>
//调用主要代码
public class RecycleViewBindAdapterTest extends BaseActivity {
AdapterManager<ImageInfo> mAM;
@Override
protected int getBindRawId() {
return R.raw.db_test_simple_recycle_view;
}
@Override
protected int getlayoutId() {
return R.layout.activity_recycle_view;
}
@Override
protected void onFinalInit(Bundle savedInstanceState) {
RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
rv.setLayoutManager(new LinearLayoutManager(
this,LinearLayoutManager.VERTICAL,false));
}
@Override
public void doBind() {
List<ImageInfo> infos = new ArrayList<>();
for(int i=0 , size = Test.URLS.length ; i < size ;i++){
infos.add(new ImageInfo(Test.URLS[i],"desc_"+i));
}
//ItemHandler 是item的事件处理器
mAM = mDataBinder.bindAdapter(R.id.rv, infos,
new ListViewBindAdapterTest.ItemHandler(
getToaster()));
}
}
//ItemHandler代码
public static class ItemHandler {
private final Toaster mToaster;
public ItemHandler(Toaster mToaster) {
this.mToaster = mToaster;
}
public void onItemClick(View v, Integer position,ImageInfo item,
AdapterManager<?> am){
mToaster.show("ItemHandler_onItemClick: position = " +
position + " ,item = " + item);
if(item.isSelected()){
am.getSelectHelper().setUnselected(position);
}else{
am.getSelectHelper().setSelected(position);
}
}
public void onTextClick(View v, Integer position,ImageInfo item,
AdapterManager<?> am){
mToaster.show("on text click: position = " + position +
" ,item = " + item);
}
}
4, 小结.
个人感觉本框架还是不错的,不过还有些地方待完善。
比如带运算符表达式的支持,代码自动生成(预计后面将会支持)。手势图片(即将支持).
Google毕竟有官方固定的人力支持,而android-databinding目前就1个人负责维护. ~~~~
诚心邀请有意愿想为开源做贡献的朋友来参加,把这个项目做得更好,更完善。
备注: 以上示例
Google databinding主要来自:http://blog.youkuaiyun.com/jdsjlzx/article/details/48133293
Android-databinding 来自: https://github.com/LightSun/android-databinding 的sample
不知道这是什么? 参见我之前写的博客: http://blog.youkuaiyun.com/pkjjun2012/article/details/50286621.
或者直接进入Github ,主页有相关文档(中文版or英文版)