【IOC 控制反转】Android 视图依赖注入 ( 视图依赖注入步骤 | 视图依赖注入代码示例 )
总结
Android 依赖注入的核心就是通过反射获取 类 / 方法 / 字段 上的注解 , 以及注解属性 ; 在 Activity 基类中 , 获取该注解 以及 注解属性 , 进行相关操作 ;
一、Android 视图依赖注入步骤
Android 视图依赖注入步骤 :
- ① 声明注解 : 声明视图注入注解
BindBiew
; - ② 客户端 Activity : 定义
MainActivity
, 继承BaseActivity
, 在属性字段上使用@BindBiew
注解注入视图 ; - ③ IOC 库中的 Activity 父类 : 定义
BaseActivity
, 在BaseActivity
中的onCreate
方法中 , 处理依赖注入相关逻辑 ; - ④ 依赖注入逻辑 : 获取
Activity
类 , 并使用反射获取类中的所有属性字段 , 获取所有的@BindBiew
注解 , 如果找到该注解 , 执行findViewById
获取视图组件对象 , 并赋值给Activity
中的属性字段 ;
二、Android 布局依赖注入示例
1、创建依赖注入库
首先在 Android 应用中 , 创建一个 " Android Library " ,
设置主应用依赖该 Android 依赖库 :
dependencies {
implementation project(path: ':ioc_lib')
}
- 1
- 2
- 3
2、声明注解
创建如下注解 :
package kim.hsl.ioc_lib;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
* 用于依赖注入视图
*/
@Target(ElementType.FIELD) // 该注解作用于字段上
@Retention(RetentionPolicy.RUNTIME) // 注解保留到运行时
public @interface BindView {
int value(); // 接收 int 类型值
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
@Target(ElementType.FIELD)
表示该注解作用于属性字段上 ;
@Retention(RetentionPolicy.SOURCE)
注解保留到源码期 , Java 源码时期 RetentionPolicy.SOURCE
-> Class 字节码时期 RetentionPolicy.CLASS
-> JVM 运行时时期 RetentionPolicy.RUNTIME
;
int value()
表示该注解接收一个 int
类型的值 ;
3、Activity 基类
package kim.hsl.ioc_lib;
import android.app.Activity;
import android.os.Bundle;
import androidx.annotation.Nullable;
public class BaseActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 在此处注入布局
// 此处传入的 Activity 参数是 MainActivity 子类对象
InjectUtils.inject(this);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
4、依赖注入工具类
将上一篇博客 【IOC 控制反转】Android 布局依赖注入 ( 布局依赖注入步骤 | 布局依赖注入代码示例 ) 中的布局注入 , 抽到 injectLayout
方法中 ; 将注入视图组件定义在 injectViews
方法中 ;
package kim.hsl.ioc_lib;
import android.app.Activity;
import android.view.View;
import java.lang.reflect.Field;
public class InjectUtils {
/**
* 为 Activity 注入布局
* @param activity 该 Activity 是继承了 BaseActivity 的 MainActivity 实例对象
*/
public static void inject(Activity activity) {
// 注入布局文件
injectLayout(activity);
// 注入视图组件
injectViews(activity);
}
/**
* 注入布局文件
*/
private static void injectLayout(Activity activity) {
// 获取 Class 字节码对象
Class<? extends Activity> clazz = activity.getClass();
// 反射获取类上的注解
ContentView contentView = clazz.getAnnotation(ContentView.class);
// 获取注解中的布局 ID
int layoutId = contentView.value();
// 为 Activity 设置显示的布局
activity.setContentView(layoutId);
}
/**
* 注入视图组件
*/
private static void injectViews(Activity activity) {
// 获取 Class 字节码对象
Class<? extends Activity> clazz = activity.getClass();
// 获取类的属性字段
Field[] fields = clazz.getDeclaredFields();
// 循环遍历类的属性字段
for (int i = 0; i < fields.length; i ++) {
// 获取字段
Field field = fields[i];
// 属性有可能是私有的, 这里设置可访问性
field.setAccessible(true);
// 获取字段上的注解, @BindView 注解
// 注意不是所有的属性字段都有 @BindView 注解
BindView bindView = field.getAnnotation(BindView.class);
if (bindView == null) {
// 如果没有获取到 BindView 注解 , 执行下一次循环
continue;
}
// 获取注入的视图组件
int viewId = bindView.value();
// 根据组件 id 获取对应组件对象
View view = activity.findViewById(viewId);
try {
// 通过反射设置 Activity 的对应属性字段的值
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
5、客户端 Activity
package kim.hsl.ioc_demo;
import android.util.Log;
import android.widget.TextView;
import kim.hsl.ioc_lib.BaseActivity;
import kim.hsl.ioc_lib.BindView;
import kim.hsl.ioc_lib.ContentView;
/**
* 当该 MainActivity 启动时 , 调用 BaseActivity 的 onCreate 方法
* 在 BaseActivity 的 onCreate 方法中注入布局
*/
@ContentView(R.layout.activity_main) // 布局注入
public class MainActivity extends BaseActivity {
/**
* 视图注入
*/
@BindView(R.id.textView)
private TextView textView;
@Override
protected void onResume() {
super.onResume();
// 验证 textView 是否注入成功
Log.i("MainActivity", "textView : " + textView);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
运行结果 :
Logcat 打印结果 :
I/MainActivity: textView : android.widget.TextView{fe85f76 V.ED..... ......ID 0,0-0,0 #7f08017e app:id/textView}
- 1
三、博客源码
GitHub : https://github.com/han1202012/IOC_Demo
CSDN : https://download.csdn.net/download/han1202012/24031128
文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。
原文链接:hanshuliang.blog.csdn.net/article/details/120404805
- 点赞
- 收藏
- 关注作者
评论(0)