Android页面跳转使用自定义注解+反射实现参数注入,同理用注解+反射实现Butterknife功能

Java注解分类(注解就是一个标记而已 单独使用没有任何意义 一般结合反射使用)

1.标准注解

@Override、@Deprecated、@SuppressWarnings等 ,使用这些注解后编译器就会进行检查

2.元注解 (注解上面的注解)

@Retention(重点)、@Target(重点)、@Inherited(继承注解用的极少)、@Documented(javac可以生成文件记录)、@Repeatable 等 ,元注解也是Java自带的标准注解,只不过用于修饰注解,比较特殊

3. 自定义注解 (本章重点)

在我们自定义注解之前,我们需要把元注解彻底搞懂,否则自定义注解的时候我们完全不知道代码为什么这么写
在这里插入图片描述
这里的@Retention 和 @Target非常重要

3.1 @Retention(用来定义该注解在哪一个级别可用 )
//注解信息会保留在源文件、类文件中,在执行的时也加载到Java的JVM中,因此可以反射性的读取
@Retention(RetentionPolicy.RUNTIME)
//此注解类型的信息只会记录在源文件中,编译时将被编译器丢弃,也就是说不会保存在编译好的类信息中
@Retention(RetentionPolicy.SOURCE)//
//编译器将注解记录在类文件中(class文件中),但不会加载到JVM中。如果一个注解声明没指定范围,则系统默认值就是Class
@Retention(RetentionPolicy.CLASS)//
package java.lang.annotation;
public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}

总结一下
在这里插入图片描述

3.2 @Target 用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Target(ElementType.FIELD)//用于字段或者属性
@Target(ElementType.TYPE)//用于类、接口、枚举类型
@Target(ElementType.CONSTRUCTOR)//用于构造函数
@Target(ElementType.PARAMETER)//用于方法的参数
@Target(ElementType.METHOD)//用于方法
@Target(ElementType.LOCAL_VARIABLE)//用于局部变量

以上是重点 其他的参数自行去ElementType类看一下 我们一般自定义注解的使用范围基于以上就够用了
接下来就是重点了!!!接下来就是重点了!!!接下来就是重点了!!!

4. 自定义注解步骤(结合本章需求实现)

4.1 自定义注解类(@interface 这里的interface和接口的定义没有任何关系,不要搞混)

package inject;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 //注解信息会保留在源文件、类文件中,在执行的时也加载到Java的JVM中,因此可以反射性的读取(使用级别)
@Retention(RetentionPolicy.RUNTIME)
//用于字段或者属性(使用范围)
@Target(ElementType.FIELD)
public @interface InjectView2 {
    String paramsKey() default "" ;//此函数 就是我们平时getIntent().getXXX(key)  key
}

4.2 定义一个注解工具类

package inject;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.widget.TextView;
import java.lang.reflect.Field;
import java.util.Arrays;

public class InjectUtils2 {

    public static void injectParams(Activity activity) {
        Class<? extends Activity> aClass = activity.getClass();
        Intent intent = activity.getIntent();
        Bundle bundle = intent.getExtras();
        if (bundle == null) {
            return;
        }
        Field[] fields = aClass.getDeclaredFields();//获取属性数组
        for (Field f : fields) {
            //判断是否被InjectView2修饰通过注解获取值
            if (f.isAnnotationPresent(InjectView2.class)) {
                //得到注解
                InjectView2 annotation = f.getAnnotation(InjectView2.class);
                String paramsKey = TextUtils.isEmpty(annotation.paramsKey())?f.getName():annotation.paramsKey();
                //判断当前的bundle是否包含key
                if (!bundle.containsKey(paramsKey)) {
                    return;
                }
                //这里一定要用bundle去获取值  intent本质也是通过bundle传值 不要用getIntent().getXXX()去获取值
                Object oValue = bundle.get(paramsKey);
                //这里特殊处理一下实现了 Parcelable的传值
                //获取属性的type
                Class<?> fieldType = f.getType();
                //判断当前属性如果是实现了Parcelable接口的数组  一般用fieldType.isAssignableFrom(String.class) 数组特殊
                if (fieldType.isArray()) {
                    //再去判断数组中单个元素的属性  如果单个属性是Parcelable(子类)数组 此时需要吧获取到的value强转为数组
                    Class<?> componentType = fieldType.getComponentType();
                    if (Parcelable.class.isAssignableFrom(componentType)) {
                        Object[] newValue = (Object[]) oValue;
                        //创建一个数组并且赋值给oValue
                        Object[] parcelables = Arrays.copyOf(newValue, newValue.length, Parcelable[].class);
                        oValue = parcelables;
                    }
                }
                f.setAccessible(true);//设置可访问  防止是private属性
                try {
                    f.set(activity, oValue);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


我们看一下使用

package com.lvyb.javaapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;

import inject.InjectUtils;
import inject.InjectView;
import inject.Person;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, MainActivity2.class);
        intent.putExtra(Constans.NAME, "张三");
        intent.putExtra(Constans.AGE, 69);
        intent.putExtra(Constans.PERSON, new Person("123", "https://www.biadu.com"));
        intent.putExtra(Constans.PHONE, "15xxxxxxx793");
        intent.putExtra(Constans.SEX, Integer.valueOf(36));
        startActivity(intent);
    }
}
package com.lvyb.javaapplication;
public class Constans {
    public static final String NAME = "name";
    public static final String AGE = "age";
    public static final String PHONE = "phone";
    public static final String PERSON = "person";
    public static final String SEX = "sex";
}

package com.lvyb.javaapplication;

import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import inject.InjectUtils2;
import inject.InjectView2;
import inject.Person;

public class MainActivity2 extends AppCompatActivity {
    @InjectView2(paramsKey = Constans.NAME)
    String name;
    @InjectView2(paramsKey = Constans.AGE)
    int age;
    @InjectView2//这里不给key 默认用phone当做key
    String phone;//这里的参数我没有注解  此时我用key = phone来获取值 正常的getIntent.getString去获取
    @InjectView2(paramsKey = Constans.PERSON)
    Person person;
    @InjectView2(paramsKey = Constans.SEX)
    Integer sex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        InjectUtils2.injectParams(this);
        Log.d("ceshi", "onCreate: ====" + name + "======" + age + "======" + phone
                + "=======" + person.getTag() + "=======" + person.getUrl() + "=======" + sex);
    }


}

总结

其实自定义注解+反射去实现这种在很多框架中都有实现 也可以自定义注解+反射实现findviewbyid 类似早期的Butterknife ,
感兴趣的同学完全可以去实现一下 非常简单 但是多少会有性能问题 留给大家一个想象的空间 ,通常网上说的早期的Butterknife 影响性能说的是什么地方

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值