【IOC 控制反转】Android 视图依赖注入 ( 视图依赖注入步骤 | 视图依赖注入代码示例 )

举报
韩曙亮 发表于 2022/01/12 22:48:25 2022/01/12
【摘要】 文章目录 总结一、Android 视图依赖注入步骤二、Android 布局依赖注入示例1、创建依赖注入库2、声明注解3、Activity 基类4、依赖注入工具类5、客户端 Activity 三...

总结

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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。