关闭

自定义Android 注解

标签: androidjava
119人阅读 评论(0) 收藏 举报
分类:

基础介绍

Java注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。

(1)元注解
元注解是指注解的注解。有@Retention @Target @Document @Inherited这四种。

(2)@Retention: 定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到

(3)@Target:定义注解的作用目标
其定义的源码为:
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包

(4)@Document:说明该注解将被包含在javadoc中

(5)@Inherited:说明子类可以继承父类中的该注解

举个栗子

这个例子实现了一个findViewById功能。
注解

package com.example.basedemo.annotation.diy;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {

    int value();

    /* parent view id */
    int parentId() default 0;
}

注解处理

package com.example.basedemo.annotation.diy;

import android.app.Activity;
import android.view.View;

import java.lang.reflect.Field;


public class ViewUtils {

    private ViewUtils() {
    }

    public static void inject(Activity activity) {
        injectObject(activity, new ViewFinder(activity));
    }

    @SuppressWarnings("ConstantConditions")
    private static void injectObject(Object handler, ViewFinder finder) {

        Class<?> handlerType = handler.getClass();

        // inject view
        Field[] fields = handlerType.getDeclaredFields();
        if (fields != null && fields.length > 0) {
            for (Field field : fields) {
                ViewInject viewInject = field.getAnnotation(ViewInject.class);
                if (viewInject != null) {
                    try {
                        View view = finder.findViewById(viewInject.value(), viewInject.parentId());
                        if (view != null) {
                            field.setAccessible(true);
                            field.set(handler, view);
                        }
                    } catch (Throwable e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }

}
package com.example.basedemo.annotation.diy;

import android.app.Activity;
import android.view.View;

public class ViewFinder {


    private Activity activity;


    public ViewFinder(Activity activity) {
        this.activity = activity;
    }

    public View findViewById(int id) {
        return  activity.findViewById(id);
    }

    public View findViewById(int id, int pid) {
        View pView = null;
        if (pid > 0) {
            pView = this.findViewById(pid);
        }

        View view = null;
        if (pView != null) {
            view = pView.findViewById(id);
        } else {
            view = this.findViewById(id);
        }
        return view;
    }


}

Activity调用

package com.example.basedemo.annotation.diy;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.example.basedemo.R;

public class DIYAnnotationActivity extends AppCompatActivity {


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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_annotation);

        ViewUtils.inject(this);

        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                textView.setText("成功了!");
            }
        });

    }


}

布局只有一个textview,这里就不罗列布局了。
——————OK,到这一步你已经成功了————————

——————下面为增加版————————
如果上面的还不够过瘾,想添加上点击事件注解,那也没问题。
定义一个onclick声明

package com.example.basedemo.annotation.diy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
    int[] value();

    int[] parentId() default 0;
}

然后在ViewUtils里声明多一个方法。这是用了Java的动态代理方法。

public class ViewUtils {
    ......省略
    public static void inject(Activity activity) {
        injectObject(activity, new ViewFinder(activity));
        injectEvent(activity);
    }
    ......省略
    private static void injectEvent(final Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        for (final Method methodY : methods) {
            OnClick click = methodY.getAnnotation(OnClick.class);
            if (click != null) {

                int[] viewId = click.value();
                methodY.setAccessible(true);
                Object listener = Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(),
                        new Class[]{View.OnClickListener.class}, new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                return methodY.invoke(activity, args);
                            }
                        });

                try {
                    for (int id : viewId) {
                        View v = activity.findViewById(id);
                        Method setClickListener = v.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
                        setClickListener.invoke(v, listener);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
 }

在activity里面调用(布局自行添加)

    @OnClick(R.id.tb_2)
    public void onClick(View v) {
        textView.setText("你按了button2");
    }

这时候你又发现你又成功了。
————————————————————

—————来来来,继续升级———————
给setcontentview注解
先设置注解

package com.example.basedemo.annotation.diy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
    int value();
}

然后设置注解处理

    public static void injectContentView(Object handler){
        Class<?> handlerType = handler.getClass();
        // inject ContentView

        ContentView contentView = handlerType.getAnnotation(ContentView.class);
        if (contentView != null) {
            try {
                Method setContentViewMethod = handlerType.getMethod("setContentView", int.class);
                setContentViewMethod.invoke(handler, contentView.value());
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }

activity里面调用

@ContentView(R.layout.activity_annotation)
public class DIYAnnotationActivity extends AppCompatActivity {


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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_annotation);
        ViewUtils.injectContentView(this);

        ViewUtils.inject(this);

        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                textView.setText("成功了!");
            }
        });

    }

    @OnClick(R.id.tb_2)
    public void onClick(View v) {
        textView.setText("你按了button2");
    }

}
0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

Android中的自定义注解

转载请标明出处: http://blog.csdn.net/hai_qing_xu_kong/article/details/51761308 本文出自:【顾林海的博客】 前言目前注解的使...
  • GULINHAI12
  • GULINHAI12
  • 2016-06-28 23:49
  • 7341

6、android:使用自定义注解精简代码

1、引言这篇文章讲的仍旧是封装,只不过这次是使用注解。关于自定义注解的使用,注解的分类这些知识不在本博客讲解范围之类,网上度娘一搜一大把。本系类博客主要讲解的实战开发,更注重的是讲解编程思想,而不是把...
  • q649381130
  • q649381130
  • 2016-06-05 22:57
  • 6709

Android中的自定义注解(反射实现-运行时注解)

预备知识: Java注解基础 Java反射原理 Java动态代理一、布局文件的注解 我们在Android开发的时候,总是会写到setContentView方法,为了避免每次都写重复的代码,我们...
  • hp910315
  • hp910315
  • 2016-04-20 12:28
  • 5784

android自定义注解实现findview和click

  • 2016-08-16 17:56
  • 8.21MB
  • 下载

Android自定义注解

  • 2017-03-14 14:57
  • 6KB
  • 下载

学会android自定义注解,只需3分钟

**学会android自定义注解,只需3分钟** 要学习自定义注解,首先我们要知道注解是什么An annotation is a form of metadata, that can be adde...
  • oMuXiaoZuo
  • oMuXiaoZuo
  • 2018-01-01 01:28
  • 38

android自定义注解初始化布局控件(二)

android中通过自定义注解代替setContentView
  • mockingbirds
  • mockingbirds
  • 2014-11-14 23:09
  • 1339

Android 自定义编译时注解1 - 简单的例子

java Type 详解java 反射机制详解注解使用入门(一)前言记得去年的时候写过一篇博客 注解使用入门(一),这篇博客主要介绍了注解的一些基本知识,以及基于运行时注解的 Demo。今天这篇博客主...
  • gdutxiaoxu
  • gdutxiaoxu
  • 2017-04-19 19:17
  • 1035

Android进阶之自定义注解

Java进阶之注解本篇文章内容包括: 注解的概念 元注解 自定义注解 Android自定义编译时注解 如果使用过ButterKnife, EventBus, Retrofit, Dagger等框架,...
  • SmarxPan
  • SmarxPan
  • 2016-06-23 19:23
  • 372

Android,几分钟教你怎么应用自定义注解

相信各位Android程序猿都了解过 ButterKnife 这个高效的注解,对于 InjectView 高效的替代findViewId更是熟之又熟。以下代码:@InjectView(R.id.tex...
  • yyeeqe_sy
  • yyeeqe_sy
  • 2016-08-19 17:01
  • 147
    个人资料
    • 访问:36209次
    • 积分:676
    • 等级:
    • 排名:千里之外
    • 原创:31篇
    • 转载:1篇
    • 译文:0篇
    • 评论:6条
    最新评论