【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;
    }
}
相关推荐
还鮟2 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡3 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi003 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil5 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你5 小时前
Android View的绘制原理详解
android
移动开发者1号8 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号8 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best13 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk13 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭18 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin