【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;
    }
}
相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui