自定义注解

对注解一直不是很了解。最近得空,学习一下自定义注解,写了一个小Demo。

编写一个替代findViewById的注解

1. 先定义一个注解

注解遵循: public @interface 注解名 {方法参数}

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

2. 编写一个类,去实现注解内容

public class AnnotationView {
    public static void getView(AppCompatActivity activity) {
        //获取Activity中的全部成员变量
        Field[] declaredFields = activity.getClass().getDeclaredFields();
        //遍历成员变量
        for (Field field : declaredFields) {
            //判断是否存在注解
            if (field.getAnnotations() != null) {
                //判断注解内容是否是我们自定义的
                if (field.isAnnotationPresent(ViewInject.class)) {
                    //如果是的话,设置该成员变量允许访问控制
                    field.setAccessible(true);
                    //获得注解实例
                    ViewInject ViewInject = field.getAnnotation(ViewInject.class);
                    try {
                        //为成员变量实现注解方法
                        field.set(activity, activity.findViewById(ViewInject.value()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

3. 使用该注解

public class MainActivity extends BaseActivity {

	//使用注解
    @ViewInject(R.id.text)
    private TextView textView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		//实现注解方法
        AnnotationView.getView(this);
        //点击测试
        textView.setOnClickListener(v -> Log.d("MainActivity", this.textView.getText().toString()));
    }
}

//输出 :com.example.annotation D/MainActivity: Hello World!

4. 问题

4.1 把实现注解方法放到BaseActivity中NPE了。

本想将 AnnotationView.getView() 放到BaseActivity中,这样每个Activity就都可以直接使用注解方法了,但发现会显示找不到View。
分析是因为先执行了注解,然后在onCreate中再执行了实现注解方法,此时布局还未加载,所以导致View未能执行findViewById方法。
以上分析为猜测,具体原因和解决办法还未确定。

4.2 一个解决办法

在寻找问题原因的时候,看到了另一个例子,作者将加载布局也做成了注解。此时便不再存在该问题。
这也变相印证了上面问题的原因猜测。

//布局注解类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LayoutInject {
    int value() default -1;
}
//view注解类
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
    int value() default -1;
}
//BaseActivity
public class InjectActivity extends AppCompatActivity {
    private int mLayoutId = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        displayInjectLayout();
        displayInjectView();
    }

    /**
     * 解析注解view id
     */
    private void displayInjectView() {
        if (mLayoutId <=0){return ;}
        Class<?> clazz = this.getClass();
        Field[] fields = clazz.getDeclaredFields();//获得声明的成员变量
        for (Field field : fields) {
            //判断是否有注解
            try {
                if (field.getAnnotations() != null) {
                    if (field.isAnnotationPresent(ViewInject.class)) {//如果属于这个注解
                        //为这个控件设置属性
                        field.setAccessible(true);//允许修改反射属性
                        ViewInject inject = field.getAnnotation(ViewInject.class);
                        field.set(this, this.findViewById(inject.value()));
                    }
                }
            } catch (Exception e) {
//                throw new InterruptedException("not found view id!");
            }
        }
    }

    /**
     * 注解布局Layout id
     */
    private void displayInjectLayout() {
        Class<?> clazz = this.getClass();
        if (clazz.getAnnotations() != null){
            if (clazz.isAnnotationPresent(LayoutInject.class)){
                LayoutInject inject = clazz.getAnnotation(LayoutInject.class);
                mLayoutId = inject.value();
                setContentView(mLayoutId);
            }
        }
    }
}
//MainActivity
@LayoutInject(R.layout.activity_main)
public class MainActivity extends InjectActivity {

    @ViewInject(R.id.text)
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //  使用注解方式加载布局
		//  setContentView(R.layout.activity_main);
        textView.setOnClickListener(v -> Log.d("MainActivity", this.textView.getText().toString()));
    }
}

5. 参考引用

注解中涉及到的内容很多,我这里也仅是一个Demo,用于理解注解是如何实现的。
参考资料:
Android注解快速入门和实用解析
Android注解-看这篇文章就够了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值