注解、反射的简单用法

本文介绍如何在Android项目中使用自定义注解,包括@BindOnclick、@ImitationDeclared和@InjectView等,实现视图绑定和点击事件处理。详细展示了ButtknifeUtils类的实现,用于反射处理注解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我们需要现在原有的工程中新建一个Studio Model reflectlibrery

reflectlibrery 中 BindOnclick

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD,ElementType.METHOD})
public @interface BindOnclick {
    int [] value() default -1;
}

reflectlibrery 中 ImitationDeclared

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ImitationDeclared {
    int value() default  -1;
}

reflectlibrery 中 InjectView

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectView {
    int value() default  -1;
}

reflectlibrery 中 ButtknifeUtils

package jiaoyibo.bawei.com.reflectlibrery;

import android.app.Activity;
import android.graphics.Paint;
import android.view.View;
import android.widget.TextView;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * <p>文件描述:<p>
 * <p>作者:JYB<p>
 * <p>创建时间:2019/3/13<p>
 * <p>更改时间:2019/3/13<p>
 * <p>版本号:1<p>
 */
public class ButtknifeUtils {
    public static void injectView(final Activity activity) throws IllegalAccessException{
        //找到被InjectView注解的控件 2、通过反射拿到注解中的资源 3、通过findViewById把xml中的对象绑定给 被注解修饰的控件
        Class<Activity> aClass = (Class<Activity>) activity.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        //帮助我们findViewById
        for (Field field:declaredFields){
            //该属性是否被InjectView注解修饰
            if(field.isAnnotationPresent(InjectView.class)){
                InjectView annotation = field.getAnnotation(InjectView.class);
                int id = annotation.value();
                View view = activity.findViewById(id);
                //可访问
                field.setAccessible(true);
                //给控件赋值
                field.set(activity,view);
                if(field.isAnnotationPresent(ImitationDeclared.class)){
                    if(view instanceof TextView){
                        ((TextView)view).getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
                    }
                }
            }
        }
        //帮助我们找点击事件的方法
        Method[] declareMethods = aClass.getDeclaredMethods();
        for(final Method method:declareMethods){
            //该属性是否被InjectView注解修饰
            if(method.isAnnotationPresent(BindOnclick.class)){
                //获取注解对象,为了拿注解中的属性 id
                BindOnclick annotation = method.getAnnotation(BindOnclick.class);
                int[] ids = annotation.value();
                for(int id:ids){
                    View view = activity.findViewById(id);
                    //可访问
                    method.setAccessible(true);
                    //给控件赋值
                    view.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            try {
                                //调用一下被BindOnclick注解修饰的方法
                                method.invoke(activity,v);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            }
        }
    }
}

写完之后,别忘了到依赖库关联一下

接着就在自己的项目中新建一个person数据

package jiaoyibo.bawei.com.zhujie;

/**
 * <p>文件描述:<p>
 * <p>作者:JYB<p>
 * <p>创建时间:2019/3/13<p>
 * <p>更改时间:2019/3/13<p>
 * <p>版本号:1<p>
 */
@Deprecated
public class Person {
    private String name;
    public int age;

    public Person(){

    }
    @Deprecated
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Deprecated
    public Person(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }
    @Deprecated
    public int getAge() {
        return age;
    }
}

接着创建ReflctTest

package jiaoyibo.bawei.com.zhujie;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * <p>文件描述:<p>
 * <p>作者:JYB<p>
 * <p>创建时间:2019/3/13<p>
 * <p>更改时间:2019/3/13<p>
 * <p>版本号:1<p>
 */
public class ReflctTest {
    public static void main(String[] arggs) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        //方式一
        Class<Person> personClass = Person.class;
        //方式二
        Class<Person> aClass = (Class<Person>) Class.forName("jiaoyibo.bawei.com.zhujie");
        //方式三
        Person person = new Person("ddd",2);
        Class<Person> aClass2 = (Class<Person>) person.getClass();
        //在class中拿field,所有public属性
        Field[] fields = personClass.getFields();
        //在class中拿field,所有属性
        Field[] declaredFields = personClass.getDeclaredFields();
        System.out.println("======================"+ (fields.length>=declaredFields.length));

        Field field = personClass.getDeclaredField("name");
        //设置可访问、可以拿到私有的属性
        field.setAccessible(true);
        field.get(person);
        System.out.println("======================"+  field.get(person));

        Method getName = personClass.getDeclaredMethod("getName");
        getName.setAccessible(true);
        //方法对象调用方式       method.invoke(他所属的对象,方法的形参)
        getName.invoke(person);
        System.out.println("======================"+  getName.invoke(person));

        //通过反射拿到构造器,去构造一个对象
        Constructor<Person> constructor = personClass.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        Person person1 = constructor.newInstance("1510B",3);
        System.out.println("======================"+  person1.getAge());

    }
}

接下来就是我们的主页面

package jiaoyibo.bawei.com.zhujie;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import jiaoyibo.bawei.com.reflectlibrery.BindOnclick;
import jiaoyibo.bawei.com.reflectlibrery.ButtknifeUtils;
import jiaoyibo.bawei.com.reflectlibrery.ImitationDeclared;
import jiaoyibo.bawei.com.reflectlibrery.InjectView;

public class MainActivity extends AppCompatActivity {
    @ImitationDeclared()
    @InjectView(R.id.reflect_id)
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        try {
            ButtknifeUtils.injectView(this);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        textView.setText("我是自定义注解做出来的");
    }
    @BindOnclick(value = {R.id.image_test,R.id.image_test2})
    public void onclick(View view){
        switch (view.getId()){
            case R.id.image_test:
                Toast.makeText(this, "我是测试的自定义点击注解", Toast.LENGTH_LONG).show();
                break;
            case R.id.image_test2:
                Toast.makeText(this, "我是测试的自定义点击注解22222222", Toast.LENGTH_LONG).show();
                break;
        }
    }
}

下面是主页面的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/reflect_id"
        android:textSize="30sp"
        android:textColor="#ff0000"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <ImageView
        android:id="@+id/image_test"
        android:background="@color/colorPrimary"
        android:layout_centerInParent="true"
        android:layout_width="150dp"
        android:layout_height="150dp" />
    <ImageView
        android:id="@+id/image_test2"
        android:layout_below="@+id/image_test"
        android:background="@color/colorAccent"
        android:layout_centerInParent="true"
        android:layout_width="150dp"
        android:layout_height="150dp" />
</RelativeLayout>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值