一、DataBinding
1.1 在Module的build.gradle android模块中添加如下配置
代码地址 https://github.com/MichealPan9999/DataBinding-MVVM
android { dataBinding { enabled = true } }
1.2 创建一个简单的JavaBean对象
public class UserBean { private String name; //姓名 private int age; //年龄 public UserBean(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
1.3 使用了DataBinding之后的Activity的布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.zx.databindingdemo.bean.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>
1.4 MainActivity
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); UserBean userBean = new UserBean ("张三", "25"); binding.setUser(userBean ); } }
但是如果你在实际编写代码的过程中,你会发现并没有执行编译、运行之类等操作,ActivityMainBinding这个类就直接能用了,竟然还有这种操作?其实是Android Studio 这个IDE自动帮我们做了这一步,在默认情况下,系统会使用Android Studio为我们自动生成databinding相关的代码,但是这种方式生成的代码不能调试,如果你想通过点击ActivityMainBinding跳转到它的源码中,你会发现并不能如你所愿,而是会跳转到对应的布局文件中。那么如果我们确实要查看ActivityMainBinding的源码并且还想调试,我们就需要通过另外一种方式:手动编译代码。这两种方式可以通过Android Studio的设置面板修改。
1.5 引入一些高级变量variable
1.5.1 import导包及xml中添加运算
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <import type="java.util.List" /> <import type="java.util.Map" /> <import type="com.example.panzq.mvvm.bean.UserBean" /> <import type="android.view.View" /> <!--泛型的支持会在编译时期报红线,但是是可以直接运行的 但是需要通过转义字符才行,如:<号用<表示;>号用>表示;--> <variable name="list" type="List<String>" /> <variable name="map" type="Map<String,Object>" /> <variable name="array" type="String[]" /> <variable name="muser" type="UserBean" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="15dp" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{list[0]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{list.get(1)}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@{map[`key0`]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{map.get(`key1`)}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@{array[0]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{array[1]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{muser.name}" android:visibility="@{((muser.age > 18) ? View.GONE:View.VISIBLE)}" /> </LinearLayout> </layout>
ActivityMain2Binding binding = DataBindingUtil.setContentView(this, R.layout.activity_main2); List<String> list = new ArrayList<>(); list.add("List1"); list.add("List2"); binding.setList(list); HashMap<String, Object> map = new HashMap<>(); map.put("key0", "map_value0"); map.put("key1", "map_value1"); binding.setMap(map); String[] array = {"字符串1", "字符串2"}; binding.setArray(array); UserBean userBean = new UserBean("张三",18); binding.setMuser(userBean);
list和map这里我没有用List<String>和Map<String,Object>,而是用的List<String>和Map<String,Object>原因是在data中,有些字符是必须用转义字符才能编译通过,上面把<>换成转义字符的写法虽然会在编译时是红色的,但是不用担心,会编译通过的,下面给出常用的转义字符。
附:常用的转义字符
显示结果 | 描述 | 转义字符 | 十进制 |
---|---|---|---|
空格 |  ; |  ; | |
< | 小于号 | <; | <; |
> | 大于号 | >; | >; |
& | 与号 | &; | &; |
" | 引号 | "; | "; |
‘ | 撇号 | &apos; | '; |
× | 乘号 | ×; | ×; |
÷ | 除号 | ÷; | ÷; |
1.5.2 别名
如果我们import了两个不同路径,但名称相同的类,可以借助于别名来解决,别名借助alias字段来标识。
<import type="com.example.panzq.mvvm.bean.UserBean" /> <import type="com.example.panzq.mvvm.bean.UserBean" alias="UserBean2"/> ... <variable name="muser" type="UserBean" /> <variable name="muser2" type="UserBean2" /> ... <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{muser.name}" android:visibility="@{((muser.age > 18) ? View.GONE:View.VISIBLE)}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{muser2.name}" android:visibility="@{((muser2.age > 18) ? View.GONE:View.VISIBLE)}" />
UserBean userBean = new UserBean("张三",18); binding.setMuser(userBean); UserBean userBean2 = new UserBean("李四",17); binding.setMuser2(userBean2);
1.5.3 android:onClick事件处理
下面给出几种实现方式:
- 布局中引入OnClickListener的变量
- 方法调用
<variable name="clickListener" type="android.view.View.OnClickListener" /> ... <Button android:id="@+id/click_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{clickListener}" android:text="button" />
binding.setClickListener(this); ... @Override public void onClick(View view) { switch (view.getId()) { case R.id.click_btn: Toast.makeText(Main2Activity.this, "点击了按钮", Toast.LENGTH_SHORT).show(); break; } }
二 DataBinding & RecyclerView
2.1 处理找不到符号 RecyclerView问题
import android.support.v7.widget.RecyclerView;时提示找不到符号RecyclerView
2.1.1 配置aar方法
1. 找到sdk目录下的recyclerview-v7-****.aar文件,如:
D:\Program Files\androidstudio3\sdk2\extras\android\m2repository\com\android\support\recyclerview-v7\24.0.0\recyclerview-v7-24.0.0.aar
2. 将aar文件拷贝到项目的libs目录下build.gradle中加载aar文件
apply plugin: 'com.android.application'android { compileSdkVersion 28 dataBinding { enabled = true } defaultConfig { applicationId "com.example.recyclerview" minSdkVersion 22 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}repositories { flatDir { dirs 'libs' }}dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.+' implementation 'com.android.support.constraint:constraint-layout:1.0.2' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' compile(name: 'recyclerview-v7-24.0.0', ext: 'aar')}
执行完Sync Now以后便可以正常导包
import android.support.v7.widget.RecyclerView;
2.2 Adapter 配置
BaseBindRecyclerViewAdapter
public abstract class BaseBindRecyclerViewAdapter<T> extends RecyclerView.Adapter { public List<T> mList; //数据源 public LayoutInflater inflater; public BaseBindRecyclerViewAdapter(Context context, List<T> mList) { this.mList = mList; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { return onCreateMyViewHolder(viewGroup, i); } @Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) { onBindMyViewHolder(viewHolder, i); } @Override public int getItemCount() { return mList.size(); } //获取Item布局 public abstract RecyclerView.ViewHolder onCreateMyViewHolder(ViewGroup parent, int viewType); //绑定数据 public abstract void onBindMyViewHolder(RecyclerView.ViewHolder holder, int position); }
MutiItemAdapter
public class MultiItemAdapter extends BaseBindRecyclerViewAdapter<IBaseBindingAdapterItem> { public MultiItemAdapter(Context context, List<IBaseBindingAdapterItem> mList) { super(context, mList); } @Override public int getItemViewType(int position) { return mList.get(position).getItemViewType(); } @Override public RecyclerView.ViewHolder onCreateMyViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case R.layout.item_fruit: ItemFruitBinding itemFruitBinding = DataBindingUtil.inflate(inflater, R.layout.item_fruit, parent, false); return new FruitViewHolder(itemFruitBinding); case R.layout.item_text: ItemTextBinding itemTextBinding = DataBindingUtil.inflate(inflater, R.layout.item_text, parent, false); return new TextViewHolder(itemTextBinding); default: ItemFruitBinding binding = DataBindingUtil.inflate(inflater, R.layout.item_fruit, parent, false); return new FruitViewHolder(binding); } } @Override public void onBindMyViewHolder(RecyclerView.ViewHolder holder, int position) { if (holder instanceof FruitViewHolder) { FruitItem fruitBean = (FruitItem) mList.get(position); ((FruitViewHolder) holder).getBinding().setItem(fruitBean); ((FruitViewHolder) holder).getBinding().executePendingBindings(); //解决databinding闪烁问题 } else if (holder instanceof TextViewHolder) { TextItem textBean = (TextItem) mList.get(position); ((TextViewHolder) holder).getBinding().setItem(textBean); ((TextViewHolder) holder).getBinding().executePendingBindings(); //解决databinding闪烁问题 } } }
但是用了DataBinding以后,主要有3个地方发生了变化,ViewHolder, onCreateViewHolder,onBindMyViewHolder。
2.2.1 编写ViewHolder
这里我的RecyclerView有两种布局,并且布局全部是用databinding编写的
class FruitViewHolder extends RecyclerView.ViewHolder { private ItemFruitBinding binding; public ItemFruitBinding getBinding() { return binding; } public FruitViewHolder(ItemFruitBinding binding) { super(binding.getRoot()); this.binding = binding; } } ... class TextViewHolder extends RecyclerView.ViewHolder { private ItemTextBinding binding; public ItemTextBinding getBinding() { return binding; } public TextViewHolder(ItemTextBinding binding) { super(binding.getRoot()); this.binding = binding; } }
2.2.2 重写onCreateViewHodler(ViewGroup parent,int viewType)
@Override public RecyclerView.ViewHolder onCreateMyViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case R.layout.item_fruit: ItemFruitBinding itemFruitBinding = DataBindingUtil.inflate(inflater, R.layout.item_fruit, parent, false); return new FruitViewHolder(itemFruitBinding); case R.layout.item_text: ItemTextBinding itemTextBinding = DataBindingUtil.inflate(inflater, R.layout.item_text, parent, false); return new TextViewHolder(itemTextBinding); default: ItemFruitBinding binding = DataBindingUtil.inflate(inflater, R.layout.item_fruit, parent, false); return new FruitViewHolder(binding); } }
2.2.3.onBindViewHolder(RecyclerView.ViewHolder holder,int position)方法
@Override public void onBindMyViewHolder(RecyclerView.ViewHolder holder, int position) {//绑定数据 if (holder instanceof FruitViewHolder) { FruitItem fruitBean = (FruitItem) mList.get(position); ((FruitViewHolder) holder).getBinding().setItem(fruitBean); ((FruitViewHolder) holder).getBinding().executePendingBindings(); //解决databinding闪烁问题 } else if (holder instanceof TextViewHolder) { TextItem textBean = (TextItem) mList.get(position); ((TextViewHolder) holder).getBinding().setItem(textBean); ((TextViewHolder) holder).getBinding().executePendingBindings(); //解决databinding闪烁问题 } }
2.3 MainAcitivity 填充数据
public class MainActivity extends AppCompatActivity { private MultiItemAdapter multiItemAdapter; private List<IBaseBindingAdapterItem> mList = new ArrayList<>(); //数据源 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.activity_main); ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main); initData(); multiItemAdapter = new MultiItemAdapter(this,mList);//获取填充的数据 LinearLayoutManager layoutManager = new LinearLayoutManager(this, OrientationHelper.VERTICAL,false); binding.recyclerView.setLayoutManager(layoutManager); binding.recyclerView.setAdapter(multiItemAdapter);//填充数据到R.id.recyclerView } private void initData() { mList.add(new TextItem("标题1")); mList.add(new FruitItem(R.mipmap.fruit, "苹果")); mList.add(new FruitItem(R.mipmap.fruit, "香蕉")); mList.add(new TextItem("标题2")); mList.add(new TextItem("标题3")); mList.add(new FruitItem(R.mipmap.fruit, "桃子")); mList.add(new TextItem("标题4")); mList.add(new FruitItem(R.mipmap.fruit, "梨")); mList.add(new TextItem("标题5")); } }
来源:https://www.cnblogs.com/qiangge-python/p/9715138.html