【Android】注解、反射、泛型实战操作

示例1:实现ButerKnife库的自动获取view

声明view的注解:

java 复制代码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectView {
    @IdRes int value(); //view id
}

在activity中获取注解value实现findViewById:

java 复制代码
public class InjectUtil {

    public static void injectView(Activity activity) {
        Class<? extends Activity> aClass = activity.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field: declaredFields) {
            if (field.isAnnotationPresent(InjectView.class)) { //如果该field含有InjectView类注解
                InjectView annotation = field.getAnnotation(InjectView.class); //获取该注解类型对象
                View view = activity.findViewById(annotation.value());
                field.setAccessible(true);
                try {
                    field.set(activity, view);  //将该view设置给该属性对象
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

使用:

java 复制代码
class MainActivity : ComponentActivity() {
    @InjectView(R.id.btn_click)
    private var button: Button ?= null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        InjectUtil.injectView(this)
}
示例2:实现ARouter库的autowire获取传递数据

Autowired注解:

java 复制代码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
    String value();
}

获取activity的intent,从带有Autowired注解的filed中获取intent的key,将对象设置给该filed。

java 复制代码
public class InjectUtil {

    public static void injectAutowired(Activity activity) {
        Class<? extends Activity> aClass = activity.getClass();
        Intent intent = activity.getIntent();
        Bundle extras = intent.getExtras();
        if (extras == null) {
            return;
        }

        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field: declaredFields) {
            if (field.isAnnotationPresent(Autowired.class)) {
                Autowired annotation = field.getAnnotation(Autowired.class);
                String key = TextUtils.isEmpty(annotation.value()) ? field.getName() : annotation.value(); //如果设置了value,key就是value,否则key就用name
                if (!key.isEmpty()) {
                    Object obj = extras.get(key);
                    field.setAccessible(true);
                    try {
                        field.set(activity, obj);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
}

使用:

java 复制代码
public class MainActivity2 extends ComponentActivity {

    @Autowired("name")
    String name;
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        InjectUtil.injectAutowired(this);

        setContentView(R.layout.activity_main2);

        Toast.makeText(getApplicationContext(), "我的名字: " + name, Toast.LENGTH_LONG).show();
    }
}
示例3:获取某个类某个方法的所有泛型和返回类型

Person类:

java 复制代码
public class Person {
    private String userName;
    private String password;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<Person> method(List<Person> persons) {
        return new ArrayList<>(persons);
    }
}
java 复制代码
public class ReflectionGeneric {

    @RequiresApi(api = Build.VERSION_CODES.P)
    public static void inject() throws NoSuchMethodException, ClassNotFoundException {
        Method method = Person.class.getMethod("method", List.class);
        Type[] genericParameterTypes = method.getGenericParameterTypes();

        //获取泛型类型
        for (Type genericParameterType : genericParameterTypes) {
            //获取泛型里面的实际参数类型
            Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                //获取非String类型的类
                if (actualTypeArgument.getTypeName().equals("java.lang.String")) {
                    String classNamePath = actualTypeArgument.getTypeName();
                    Class<?> aClass = Class.forName(classNamePath);
                    //获得所有属性
                    Arrays.stream(aClass.getDeclaredFields()).forEach(System.out::println);
                }
            }
        }

        //获取返回类型
        Type genericReturnType = method.getGenericReturnType();
        Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
        Type actualTypeArgument = actualTypeArguments[0];
        if (actualTypeArgument.getTypeName().equals("java.lang.String")) {
            //获取参数全类名
            String classNamePath = actualTypeArgument.getTypeName();
            //根据类路径获取class文件
            Class<?> returnClass = Class.forName(classNamePath);
            //获得所有属性
            Arrays.stream(returnClass.getDeclaredFields()).forEach(System.out::println);
        }

    }

}
示例4:实现Hilt库的自动注入对象

单例对象注解和非单例对象注解:

java 复制代码
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleInject {

}

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleSingleInject {

}
java 复制代码
/**
 * 自动注入创建对象
 */
public class Hilt {
    public static Map<Class<?>, Object> instances = new ConcurrentHashMap<>();
    public static <T> T getSingleInstance(Class<T> cls) {
        try {
            //判断是否走单例
            if (!cls.isAnnotationPresent(SimpleSingleInject.class)){
                return getInstance(cls);
            }
            Object obj = instances.get(cls);
            if (null != obj) {
                return (T)obj;
            }
            //使用类锁锁代码块
            synchronized (cls) {
                if (null == instances.get(cls)) {
                    obj = getInstance(cls);
                    instances.put(cls, obj);
                }

            }
            return (T)obj;
        }
        catch (Exception e) {
            throw new RuntimeException();
        }
    }

    public static<T> T getInstance (Class<T> cls){
        //如果该class中含有SimpleInject注解的filed,则反射创建该filed对象设置给该class
        try {
            T obj = cls.newInstance();
            //返回本类申明的字段包括非public,不包括父类
            Field[] declaredFields = cls.getDeclaredFields();
            for (Field f : declaredFields) {
                //判断字段是否包含指定注解类型
                if (f.isAnnotationPresent(SimpleInject.class)) {
                    //判断字段是否为私有
                    if (!f.isAccessible()) {
                        f.setAccessible(true);
                    }
                    //再次递归调用赋值
                    f.set(obj, getInstance(f.getType()));
                }

            }
            return obj;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}

提供注解对象的module:

java 复制代码
public class Module {

    @SimpleInject
    Person person;
}

使用:

java 复制代码
public class MainActivity3 extends ComponentActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main2);

        Module singleInstance = Hilt.getSingleInstance(Module.class);

        singleInstance.person.setUserName("haha");
        singleInstance.person.setPassword("123456");

        Toast.makeText(getApplicationContext(), "我的名字: " + singleInstance.person.getUserName() + " 我的密码:" + singleInstance.person.getPassword(), Toast.LENGTH_LONG).show();
    }
}
示例5:实现Retrofit库动态代理获取请求方法的各个数据

GET、POST请求注解

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GET {
    String value();
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
    String value();
}

Retrofit的简单实现:动态代理获取method的GET、POST注解,发起请求:

java 复制代码
public class Retrofit {
    private OkHttpClient mOkHttpClient;
    private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");

    public Retrofit(OkHttpClient mOkHttpClient) {
        this.mOkHttpClient = mOkHttpClient;
    }

    public <T> T create(Class<T> service) {
        Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service}, new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                Annotation[] annotations = method.getAnnotations();
                for (Annotation annotation: annotations) {
                    if (annotation instanceof GET) {
                        return parseGet(((GET) annotation).value());
                    } else if (annotation instanceof POST){
                        return parsePost(((POST) annotation).value(), method, objects);
                    }
                }
                return null;
            }
        });
        return null;
    }

    /**
     * 处理GET请求信息获取并发起请求
     * @param url
     * @return
     */
    private Call parseGet(String url) {
        Request request = new Request.Builder()
                .get()
                .url(url)
                .build();
        return mOkHttpClient.newCall(request);
    }

    /**
     * 处理POST请求信息获取并发起请求
     * @param url
     * @return
     */
    private Call parsePost(String url, Method method, Object[] args) {
        Type[] genericParameterTypes = method.getGenericParameterTypes();//获取方法泛型
        if (genericParameterTypes.length > 0) {
            Object o = new Gson().fromJson((String) args[0], genericParameterTypes[0]);
            Request request = new Request.Builder()
                    .url(url)
                    .post(RequestBody.create(MEDIA_TYPE, o.toString()))
                    .build();
            return mOkHttpClient.newCall(request);
        }
        return null;
    }
}
相关推荐
Estar.Lee2 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
温辉_xh3 小时前
uiautomator案例
android
工业甲酰苯胺4 小时前
MySQL 主从复制之多线程复制
android·mysql·adb
少说多做3434 小时前
Android 不同情况下使用 runOnUiThread
android·java
Estar.Lee5 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
找藉口是失败者的习惯6 小时前
从传统到未来:Android XML布局 与 Jetpack Compose的全面对比
android·xml
Jinkey7 小时前
FlutterBasic - GetBuilder、Obx、GetX<Controller>、GetxController 有啥区别
android·flutter·ios
大白要努力!9 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟10 小时前
Android音频采集
android·音视频
小白也想学C11 小时前
Android 功耗分析(底层篇)
android·功耗