当前位置:网站首页>利用反射整合ViewBinding和ViewHolder
利用反射整合ViewBinding和ViewHolder
2022-06-30 03:28:00 【乐征skyline】
利用反射整合ViewBinding和ViewHolder
自从DataBinding和ViewBinding出现后,Android开发中获取界面元素就变得非常方便。即使是RecyclerView
的ViewHolder
也可以使用ViewBinding,例如下面这样
public class ItemTestHolder extends RecyclerView.ViewHolder {
private final HolderItemTestBinding binding;
public static ItemTestHolder newInstance(ViewGroup viewGroup) {
HolderItemTestBinding binding = HolderItemTestBinding.inflate(LayoutInflater.from(viewGroup.getContext()), viewGroup, false);
return new ItemTestHolder(binding);
}
public ItemTestHolder(@NonNull HolderItemTestBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
public void setData(String text){
binding.tvName.setText(text);
}
}
或者
public class ItemTestHolder extends RecyclerView.ViewHolder {
private final HolderItemTestBinding binding;
public ItemTestHolder(@NonNull ViewGroup viewGroup) {
super(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.holder_item_test, viewGroup, false));
this.binding = HolderItemTestBinding.bind(itemView);
}
public void setData(String text) {
binding.tvName.setText(text);
}
}
但是,像这样每次写一遍....inflate(...)
的代码也是一件挺麻烦的事情,因此本文就来介绍一种极简的方式来整合ViewBinding和ViewHolder,最终实现像下面这样的代码:
public class ItemTestHolder extends ViewBindingHolder<HolderItemTestBinding> {
public ItemTestHolder(@NonNull ViewGroup viewGroup) {
super(viewGroup);
}
public void setData(String text) {
getBinding().tvName.setText(text);
}
}
ViewBindingHolder基类的实现
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;
import com.yr.corelib.util.ReflectUtils;
import java.lang.reflect.*;
@Keep
public abstract class ViewBindingHolder<B extends ViewBinding> extends RecyclerView.ViewHolder {
private final B binding;
public ViewBindingHolder(@NonNull ViewGroup viewGroup) {
super(viewGroup);
try {
Class<? extends ViewBinding> aClass = ReflectUtils.findParameterizedClass(getClass().getGenericSuperclass(), ViewBinding.class);
Method inflateMethod = aClass.getMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
try {
binding = (B) inflateMethod.invoke(null, LayoutInflater.from(viewGroup.getContext()), viewGroup, false);
modifyItemView(binding.getRoot());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
} catch (Exception e) {
throw new RuntimeException("Something wrong when create Binding:", e);
}
}
public B getBinding() {
return binding;
}
private void modifyItemView(Object newFieldValue) throws Exception {
Field field = RecyclerView.ViewHolder.class.getDeclaredField("itemView");
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(this, newFieldValue);
}
}
2. ReflectUtils反射工具
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class ReflectUtils {
public static <T> Class<? extends T> findParameterizedClass(Class<?> aClass, Class<T> targetClass) {
return findParameterizedClass(aClass.getGenericSuperclass(), targetClass);
}
public static <T> Class<? extends T> findParameterizedClass(Type type, Class<T> targetClass) {
if (type instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
for (Type typeArgument : typeArguments) {
if (typeArgument instanceof Class) {
if (targetClass.isAssignableFrom((Class<?>) typeArgument)) {
return (Class<? extends T>) typeArgument;
}
} else {
throw new IllegalStateException("typeArgument is not a Class");
}
}
Type rawType = ((ParameterizedType) type).getRawType();
if (rawType.equals(Object.class)) {
return null;
} else {
return findParameterizedClass(rawType, targetClass);
}
} else if (type instanceof Class) {
if (type.equals(Object.class)) {
return null;
} else {
Type superclass = ((Class<?>) type).getGenericSuperclass();
return findParameterizedClass(superclass, targetClass);
}
} else {
throw new IllegalStateException("type is not ParameterizedType or Class!");
}
}
}
3. 用法说明
ViewBindingHolder
的使用非常简单,假设你要新建一个名为ImageViewHolder
,而布局文件名为holder_image.xml
(对应ViewBinding类为HolderImage
),那么在配置好ViewBinding后,进行以下步骤:
- 让
ImageViewHolder
继承ViewBindingHolder
; - 将
HolderImage
作为ViewBindingHolder
的泛型参数; - 编写/自动生成一个
ViewHolder
的默认构造方法;
然后就可以通过getBinding
来获取对应的ViewBinding对象了。
当然,也可以不用显式继承,而是匿名内部类的方式来使用ViewBindingHolder
,例如:
RecyclerView.Adapter<ViewBindingHolder<HolderItemTestBinding>> adapter = new RecyclerView.Adapter<ViewBindingHolder<HolderItemTestBinding>>() {
@NonNull
@Override
public ViewBindingHolder<HolderItemTestBinding> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewBindingHolder<HolderItemTestBinding>(parent) {
};
}
@Override
public void onBindViewHolder(@NonNull ViewBindingHolder<HolderItemTestBinding> holder, int position) {
holder.getBinding().tvName.setText("");
}
@Override
public int getItemCount() {
return 1;
}
};
4. DataBindingHolder的实现
同理,DataBinding也可以采用这种方式封装成一个DataBindingHolder
:
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.databinding.ViewDataBinding;
import androidx.recyclerview.widget.RecyclerView;
import com.yr.corelib.util.ReflectUtils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@Keep
public abstract class DataBindingHolder<B extends ViewDataBinding> extends RecyclerView.ViewHolder {
private final B binding;
public DataBindingHolder(@NonNull ViewGroup viewGroup) {
super(viewGroup);
try {
Class<? extends ViewDataBinding> aClass = ReflectUtils.findParameterizedClass(getClass().getGenericSuperclass(), ViewDataBinding.class);
Method inflateMethod = aClass.getMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class);
try {
binding = (B) inflateMethod.invoke(null, LayoutInflater.from(viewGroup.getContext()), viewGroup, false);
modifyItemView(binding.getRoot());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
} catch (Exception e) {
throw new RuntimeException("Something wrong when create Binding:", e);
}
}
public B getBinding() {
return binding;
}
public void bind(int position) {
}
private void modifyItemView(Object newFieldValue) throws Exception {
Field field = RecyclerView.ViewHolder.class.getDeclaredField("itemView");
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(this, newFieldValue);
}
}
边栏推荐
- JS cross reference
- HOOK Native API
- Global and Chinese market of bronze valves 2022-2028: Research Report on technology, participants, trends, market size and share
- Sorting method of administrative route code letter + number
- Simple custom MVC
- General paging (2)
- How does the trading platform for speculation in spot gold ensure capital security?
- Is the largest layoff and salary cut on the internet coming?
- [wechat applet] how did the conditional rendering list render work?
- What are outer chain and inner chain?
猜你喜欢
广播模块代码在autojs4.1.1版本运行正常,但在pro7.0版本上运行报错(未解决)
Linked list: insert a node in the head
Learning cyclic redundancy CRC check
Mathematical solution of Joseph Ring
From 2500 a month, no one wants to go to the programming road of the technical director of a large factory | my ten years
QT中foreach的使用
Number of students from junior college to Senior College (III)
X Book 6.89 shield unidbg calling method
laravel9本地安裝
Redis中的Hash设计和节省内存数据结构设计
随机推荐
Possible problems in MySQL cross database operation with database name
Practical debugging skills
Auto.js学习笔记16:按项目保存到手机上,不用每次都保存单个js文件,方便调试和打包
Dripping backward (II)
hudi记录
Knowledge points of 2022 system integration project management engineer examination: software quality assurance and quality evaluation
4-4 beauty ranking (10 points)
MySQL + JSON = King fried
Global and Chinese market of medical mass notification system 2022-2028: Research Report on technology, participants, trends, market size and share
AppData文件夹下Local,Locallow和Roaming
Auto. JS learning notes 16: save to the mobile phone by project, instead of saving a single JS file every time, which is convenient for debugging and packaging
Litjson parses the generated JSON file and reads the dictionary in the JSON file
MySQL performance optimization (5): principle and implementation of master-slave synchronization
Golang BiliBili live broadcast bullet screen
Utf8 error in Oracle migration of Jincang Kingbase database
共124篇!墨天轮“高可用架构”干货文档分享(含Oracle、MySQL、PG)
An article to get you started VIM
Some common functions and precautions
Auto.js学习笔记15:autojs的UI界面基础篇2
If you can tell whether the external stock index futures trading platform I am trading is formal and safe?