当前位置:网站首页>将DataBinding整合到Activity/Fragment的一种极简方式
将DataBinding整合到Activity/Fragment的一种极简方式
2022-06-30 03:28:00 【乐征skyline】
自从Google推出DataBinding/ViewBinding后,获取视图控件变得简单、高效且安全。而Activity中原本
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
//...
}
}
这样的代码也变成了像下面这样
public class TestActivity extends AppCompatActivity {
ActivityTestBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityTestBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
//...
}
}
或
public class TestActivity extends AppCompatActivity {
ActivityTestBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_test);
//...
}
}
每次都要写一遍inflate或setContentView调用并设置一个binding字段也听麻烦的,不如原来setContentView(R.layout.activity_test)这样来的简单。因此就考虑新建一个BaseActivity来简化这个过程。
1. 最初的方案
一开始的方案如下:
public abstract class BaseActivity<B extends ViewDataBinding> extends AppCompatActivity {
private B binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, getLayoutId());
binding.setLifecycleOwner(this);
initView(binding);
}
protected abstract void initView(B binding);
protected abstract int getLayoutId();
protected B getBinding() {
return binding;
}
}
这样新建一个Activity的代码就变成了
public class TestActivity extends BaseActivity<ActivityTestBinding> {
@Override
protected void initView(ActivityTestBinding binding) {
}
@Override
protected int getLayoutId(){
return R.layout.activity_test;
}
}
这样只需要在继承BaseActivity在泛型上写上数据绑定的类型,并在自动生成的getLayoutId方法中返回对应布局id就可以了。
但是在用了一段时间这种方法后觉得每次写id也挺麻烦,有时候引用错了id启动就直接崩溃报错。因此考虑下,就想出接下来要讲述的更简单的方法。
2. 利用反射来实现更简单的整合
最终的实现效果是下面这样,只需要在泛型中编写引用的Binding类型就可以,并且在这个Activity的作用域中,可以通过getBinding方法得到对应的应用
public class TestActivity extends BaseActivity<ActivityTestBinding> {
@Override
protected void initView(ActivityTestBinding binding) {
test();
}
private void test(){
getBinding().button.setOnClickListener(v -> {
//...
});
}
}
首先我们需要一个反射工具,用于获得Activity泛型参数中ViewBinding/ViewDataBinding的子类的Class:
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!");
}
}
}
然后,我们的BaseActivity就改写为下面这样
public abstract class BaseActivity<B extends ViewDataBinding> extends AppCompatActivity {
private B binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
Class parameterizedClass = ReflectUtils.findParameterizedClass(getClass().getGenericSuperclass(), ViewBinding.class);
if (parameterizedClass == null) {
parameterizedClass = ReflectUtils.findParameterizedClass(getClass().getGenericSuperclass(), ViewDataBinding.class);
}
if (parameterizedClass == null) {
throw new IllegalStateException("not find parameterized type extends ViewBinding or ViewDataBinding");
} else {
Method inflateMethod = parameterizedClass.getMethod("inflate", LayoutInflater.class);
binding = (B) inflateMethod.invoke(null, getLayoutInflater());
}
} catch (Exception e) {
throw new RuntimeException("Something wrong when create Binding:", e);
}
if (binding == null) {
throw new RuntimeException("binding is null!");
} else {
setContentView(binding.getRoot());
binding.setLifecycleOwner(this);
initView(binding);
}
}
protected abstract void initView(B binding);
protected B getBinding() {
return binding;
}
}
3. 将这种方式推广到Fragment
我们还可以用这种方式来实现Fragment和DataBinding/ViewBinding的整合:
public abstract class BaseFragment<B extends ViewDataBinding> extends Fragment {
private B binding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
try {
Class parameterizedClass = ReflectUtils.findParameterizedClass(getClass().getGenericSuperclass(), ViewBinding.class);
if (parameterizedClass == null) {
parameterizedClass = ReflectUtils.findParameterizedClass(getClass().getGenericSuperclass(), ViewDataBinding.class);
}
if (parameterizedClass == null) {
throw new IllegalStateException("not find parameterized type extends ViewBinding or ViewDataBinding");
} else {
Method inflateMethod = parameterizedClass.getMethod("inflate", LayoutInflater.class, ViewGroup.class, Boolean.class);
binding = (B) inflateMethod.invoke(null, getLayoutInflater(), container, false);
}
} catch (Exception e) {
throw new RuntimeException("Something wrong when create Binding:", e);
}
if (binding != null) {
return binding.getRoot();
} else {
throw new RuntimeException("binding is null!");
}
}
public B getBinding() {
return binding;
}
}
边栏推荐
- Number of students from junior college to Senior College (III)
- JS 互相引用的问题
- Installation and use of yarn
- Utf8 error in Oracle migration of Jincang Kingbase database
- Auto.js学习笔记15:autojs的UI界面基础篇2
- Dripping backward (II)
- 51 single chip microcomputer indoor environment monitoring system, mq-2 smoke sensor and DHT11 temperature and humidity sensor, schematic diagram, C programming and simulation
- Hisense A7 ink screen mobile phone cannot be started
- Global and Chinese market of centrifugal pumps 2022-2028: Research Report on technology, participants, trends, market size and share
- Feign 坑
猜你喜欢

LitJson解析 生成json文件 读取json文件中的字典

OP diode limit swing
![[practical skills] how to write agile development documents](/img/38/4bab396891ce3cc42595ae8cfd45ce.png)
[practical skills] how to write agile development documents

unity input system 使用记录(实例版)

51单片机的室内环境监测系统,MQ-2烟雾传感器和DHT11温湿度传感器,原理图,C编程和仿真

Linked list: insert a node in the head

Simple custom MVC optimization

F1c100s self made development board debugging process

hudi记录

TiDB 6.0:让 TSO 更高效丨TiDB Book Rush
随机推荐
图的邻接矩阵存储 C语言实现BFS
124 articles in total! Motianlun "high availability architecture" dry goods document sharing (including Oracle, mysql, PG)
AppData文件夹下Local,Locallow和Roaming
1152_ Makefile learning_ Pattern matching rules
HOOK Native API
JS cross reference
Neo4j---性能优化
[0x0] open questions left by the principal
Global and Chinese markets for advanced wound care 2022-2028: Research Report on technology, participants, trends, market size and share
Buffer pool of MySQL notes
Litjson parses the generated JSON file and reads the dictionary in the JSON file
【常见问题】浏览器环境、node环境的模块化问题
Neo4j--- performance optimization
Openssl3.0 learning 22 provider decoder
Problem record: FEL_ lib. c:26:10: fatal error: libusb. h: There is no such file or directory
1150_ Makefile learning_ Duplicate name target processing in makefile
Product thinking - is the future of UAV express worth looking forward to?
[qt] qmap usage details
Use of foreach in QT
Global and Chinese market for nasal drug delivery devices 2022-2028: Research Report on technology, participants, trends, market size and share