四川福彩快乐12app下载-四川快乐12app官网(彩世界)
做最好的网站
来自 科学技术 2019-11-03 06:44 的文章
当前位置: 四川福彩快乐12app下载 > 科学技术 > 正文

抛弃ConfigurationManager , 实现面向对象读写配置文件

以上。

6.1、 标准 Annotation

包括 Override, Deprecated, SuppressWarnings,标准 Annotation 是指 Java 自带的几个 Annotation,上面三个分别表示重写函数,不鼓励使用(有更好方式、使用有风险或已不在维护),忽略某项 Warning

      首先看看这个类

Javapoet 是一个用来生成 .java 文件的 Java API,由 Square 开发,你可以在它的 Github 主页中了解它的基本使用方法。它的好处就是对方法、类文件和代码等的拼接进行了封装,有了它,我们就不用再按照字符串的方式去拼接出一段代码了。相比于直接使用字符串的方式,它还可以生成代码的同时直接 import 对应的引用,可以说是非常方便、快捷的一个库了。

7.4、注册处理器

我们在编译好的META-INF/services添加我们的处理器路径,谷歌已经提供一个很方便的库,帮助我们做这些东西,我们只需要在处理器工程添加依赖

compile 'com.google.auto.service:auto-service:1.0-rc2'

然后在Myprocessor中添加@AutoService(Processor.class)的注解,这样就完成了我们处理器的注册。

四川福彩快乐12app下载 1

image

编译成生成的META-INF/services中就注册了我们的MyProcessor

四川福彩快乐12app下载 2

image

接下来,我们编写一个我们自己的处理器,生成java文件,来讲解一下相关API,以及要注意的事项。

/**
 * 每一个注解处理器类都必须有一个空的构造函数,默认不写就行;
 */
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {

    //处理Element的工具类
    private Elements mElementUtils;
    //生成文件的工具
    private Filer mFiler;
    //日志信息的输出
    private Messager mMessager;


    /**
     * 这相当于每个处理器的主函数main(),你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件。
     * 输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素
     * @param annotations   请求处理的注解类型
     * @param roundEnvironment  有关当前和以前的信息环境
     * @return  如果返回 true,则这些注解已声明并且不要求后续 Processor 处理它们;
     *          如果返回 false,则这些注解未声明并且可能要求后续 Processor 处理它们
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
        Set<? extends Element> set = roundEnvironment.getElementsAnnotatedWith(MyAnnotation.class);
        for (Element element : set){
            if(element.getKind() == ElementKind.CLASS){
                TypeElement typeElement = (TypeElement) element;
                brewJavaFile(typeElement);
            }
        }
        return true;
    }

    /**
     * init()方法会被注解处理工具调用,并输入ProcessingEnviroment参数。
     * ProcessingEnviroment提供很多有用的工具类Elements, Types 和 Filer
     * @param processingEnvironment 提供给 processor 用来访问工具框架的环境
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        mElementUtils = processingEnvironment.getElementUtils();
        mFiler = processingEnvironment.getFiler();
        mMessager = processingEnvironment.getMessager();
    }

    /**
     * 这里必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称
     * @return  注解器所支持的注解类型集合,如果没有这样的类型,则返回一个空集合
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new LinkedHashSet<>();
        set.add(MyAnnotation.class.getCanonicalName());
        return set;
    }

    /**
     * 指定使用的Java版本,通常这里返回SourceVersion.latestSupported(),默认返回SourceVersion.RELEASE_6
     * @return  使用的Java版本
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    private void brewJavaFile(TypeElement pElement){
        //sayHello 方法
        MyAnnotation myAnnotation = pElement.getAnnotation(MyAnnotation.class);
        MethodSpec methodSpec = MethodSpec.methodBuilder("sayHello")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC).returns(void.class)
                .addStatement("$T.out.println($S)",System.class,"Hello" myAnnotation.value()).build();

        // class
        TypeSpec typeSpec = TypeSpec.classBuilder(pElement.getSimpleName().toString() "$$HelloWorld").addModifiers(Modifier.PUBLIC,Modifier.FINAL).addMethod(methodSpec).build();
        // 获取包路径,把我们的生成的源码放置在与被注解类中同一个包路径中
        JavaFile javaFile = JavaFile.builder(mElementUtils.getPackageOf(pElement).getQualifiedName().toString(),typeSpec).build();
        try {
            javaFile.writeTo(mFiler);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

   有经验的人一眼就可以看出,这是一个provider的基类。那么我们究竟用什么方法来解决我们的问题呢?现在我们回到基类,

用来指定注解的保留策略,比如有一些注解,当你在自己的代码中使用它们的时候你会把它写在方法上面,但是当你反编译之后却发现这些注解不在了;而有些注解反编译之后依然存在,发生这种情况的原因就是在使用该注解的时候指定了不同的参数。

6.2.2、@Target (目标)

用于指定被修饰的Annotation能用于修饰哪些程序单元,只能修饰Annotation定义。它包含一个名为value的成员变量,取值如下:

  • @Target(ElementType.ANNOTATION_TYPE): 指定该该策略的Annotation只能修饰Annotation.
  • @Target(ElementType.TYPE) : 接口、类、枚举、注解
  • @Target(ElementType.FIELD) : 成员变量(字段、枚举的常量)
  • @Target(ElementType.METHOD) : 方法
  • @Target(ElementType.PARAMETER): 方法参数
  • @Target(ElementType.CONSTRUCTOR): 构造函数
  • @Target(ElementType.LOCAL_VARIABLE): 局部变量
  • @Target(ElementType.PACKAGE): 修饰包定义
  • @Target(ElementType.TYPE_PARAMETER): java8新增,可以使用在方法参数上
  • @Target(ElementType.TYPE_USE): java8新增,修饰的注解称为Type Annotation(类型注解),Type Annotation可用在任何用到类型的地方。

比如:

@Target(ElementType.FIELD)
public @interface MyActionListener{}

四川福彩快乐12app下载 3四川福彩快乐12app下载 4 class="cnblogs_code_collapse" style="font-size: 12pt;">代码

public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">abstract style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">class style="color: #000000; font-size: 12pt;"> ConfigProvider:ProviderBase
    {
      
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">abstract style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> Load( style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> typename,  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> settings);

         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">abstract style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">void style="color: #000000; font-size: 12pt;"> Save( style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> typename,  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> settings);
        
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">abstract style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> Location( style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> typename);

    }

因为我们应用 MyKnife 的类是 MyKnifeActivity ,所以这里就生成了名为 MyKnifeActivity$ $Injector 的类。通过上面的代码,可以看出它实际上调用了 Finder 的方法来为我们的控件 textView 赋值,然后使用控件的 setOnClickListener() 方法为点击事件赋值。这里的 Finder 是我们封装的一个对象,用来从指定的源中获取控件的类,本质上还是调用了指定源的 findViewById() 方法。

6.2.5、Repeatable(可重复)

Java SE8引入的注解,表示这个注解可以在同一处多次声明

      这里为了方便大家阅读,我提供一个不是依赖注入的例子。实现一个ConfigService 代码如下:

然后,与 ButterKnife 类似的是,在使用我们的工具的时候,也需要在 Activity 的 onCreate() 中调用 bind() 方法。这里我们看下这个方法做了什么操作:

7.2、创建Android工程

定义好我们注解的MyAnnotation,接下来,我们要用这个去注解MainActivity,现在我们是在Java工程,那么我们新创建一个Android工程,里面有个MainActivity,这个工程依赖我们MyAnnotation所在的工程。

@MyAnnotation
public class MainActivity extends AppCompatActivity {

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

接下来我们就要通过自己定义的注解处理器去扫描这个注解进而生成java文件,但是在此之前,我们需要先了解注解处理的工作流程和相关API。

四川福彩快乐12app下载 5四川福彩快乐12app下载 6 class="cnblogs_code_collapse" style="font-size: 12pt;">代码

 [Serializable]
     style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">class style="color: #000000; font-size: 12pt;"> ORMConfig : ConfigBase style="color: #000000; font-size: 12pt;">< style="color: #000000; font-size: 12pt;">ORMConfig style="color: #000000; font-size: 12pt;">> style="color: #000000;">
    {
         style="color: #0000ff; font-size: 12pt;">private style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">static style="color: #000000; font-size: 12pt;"> ORMConfig _Instance  style="color: #000000; font-size: 12pt;">= style="color: #000000; font-size: 12pt;"> LoadConfig();

style="color: #000000; font-size: 12pt;">        [XmlIgnore]
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">static style="color: #000000; font-size: 12pt;"> ORMConfig Instance
        {
             style="color: #0000ff; font-size: 12pt;">get style="color: #000000; font-size: 12pt;"> {  style="color: #0000ff; font-size: 12pt;">return style="color: #000000; font-size: 12pt;"> _Instance; }
        }

         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">static style="color: #000000; font-size: 12pt;"> ORMConfig LoadConfig()
        {
             style="color: #0000ff; font-size: 12pt;">return style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> ORMConfig().Load();
        }


         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> Connection {  style="color: #0000ff; font-size: 12pt;">get style="color: #000000; font-size: 12pt;">;  style="color: #0000ff; font-size: 12pt;">set style="color: #000000; font-size: 12pt;">; }
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> DataPre {  style="color: #0000ff; font-size: 12pt;">get style="color: #000000; font-size: 12pt;">;  style="color: #0000ff; font-size: 12pt;">set style="color: #000000; font-size: 12pt;">; }
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> Provider {  style="color: #0000ff; font-size: 12pt;">get style="color: #000000; font-size: 12pt;">;  style="color: #0000ff; font-size: 12pt;">set style="color: #000000; font-size: 12pt;">; }
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> AssemblyInfo {  style="color: #0000ff; font-size: 12pt;">get style="color: #000000; font-size: 12pt;">;  style="color: #0000ff; font-size: 12pt;">set style="color: #000000; font-size: 12pt;">; }
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> DefaultDBName {  style="color: #0000ff; font-size: 12pt;">get style="color: #000000; font-size: 12pt;">;  style="color: #0000ff; font-size: 12pt;">set style="color: #000000; font-size: 12pt;">; }

    }

 

getInfo

style="font-size: 16px;">id style="font-size: 16px;">- style="font-size: 16px;">id style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">first_name style="font-size: 16px;">- style="font-size: 16px;">firstName style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">last_name style="font-size: 16px;">- style="font-size: 16px;">lastName style="font-size: 16px;">,

二、注解的作用

  • 格式检查:告诉编译器信息,比如被@Override标记的方法如果不是父类的某个方法,IDE会报错;

  • 减少配置:运行时动态处理,得到注解信息,实现代替配置文件的功能;

  • 减少重复工作:比如第三方框架xUtils,通过注解@ViewInject减少对findViewById的调用,类似的还有(ButterKnife、ActiveAndroid等);

四川福彩快乐12app下载 7四川福彩快乐12app下载 8 class="cnblogs_code_collapse" style="font-size: 12pt;">代码

style="color: #000000; font-size: 12pt;"> ORMConfig configmodel  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> ORMConfig();
style="color: #000000; font-size: 12pt;">            configmodel.AssemblyInfo  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">TestPro style="color: #800000; font-size: 12pt;">" style="color: #000000; font-size: 12pt;">;
style="color: #000000; font-size: 12pt;">            configmodel.DataPre  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">HG_ style="color: #800000; font-size: 12pt;">" style="color: #000000; font-size: 12pt;">;
style="color: #000000; font-size: 12pt;">            configmodel.DefaultDBName  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">Test_DB style="color: #800000; font-size: 12pt;">" style="color: #000000; font-size: 12pt;">;
style="color: #000000; font-size: 12pt;">            configmodel.Provider  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">SqlServer style="color: #800000; font-size: 12pt;">" style="color: #000000; font-size: 12pt;">;
style="color: #000000; font-size: 12pt;">            configmodel.Connection  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">Data Source=.;User ID=sa;Password=sasa;Initial Catalog=Test_DB style="color: #800000; font-size: 12pt;">" style="color: #000000; font-size: 12pt;">;
style="color: #000000; font-size: 12pt;">            configmodel.Save();

publicJavaFile generateFinder(){

style="font-size: 16px;">// 这里用来定义inject方法的签名

style="font-size: 16px;"> style="font-size: 16px;">MethodSpec style="font-size: 16px;">. style="font-size: 16px;">Builder style="font-size: 16px;">builder style="font-size: 16px;">= style="font-size: 16px;">MethodSpec style="font-size: 16px;">. style="font-size: 16px;">methodBuilder style="font-size: 16px;">( style="font-size: 16px;">"inject" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addModifiers style="font-size: 16px;">( style="font-size: 16px;">Modifier style="font-size: 16px;">. style="font-size: 16px;">PUBLIC style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addAnnotation style="font-size: 16px;">( style="font-size: 16px;">Override style="font-size: 16px;">. style="font-size: 16px;">class style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addParameter style="font-size: 16px;">( style="font-size: 16px;">TypeName style="font-size: 16px;">. style="font-size: 16px;">get style="font-size: 16px;">( style="font-size: 16px;">typeElement style="font-size: 16px;">. style="font-size: 16px;">asType style="font-size: 16px;">()), style="font-size: 16px;"> style="font-size: 16px;">"host" style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">Modifier style="font-size: 16px;">. style="font-size: 16px;">FINAL style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addParameter style="font-size: 16px;">( style="font-size: 16px;">TypeName style="font-size: 16px;">. style="font-size: 16px;">OBJECT style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">"source" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addParameter style="font-size: 16px;">( style="font-size: 16px;">TypeUtils style="font-size: 16px;">. style="font-size: 16px;">FINDER style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">"finder" style="font-size: 16px;">);

style="font-size: 16px;">// 这里用来定义inject方法中@BindView注解的绑定过程

style="font-size: 16px;"> style="font-size: 16px;">for style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">BindViewField style="font-size: 16px;">field: bindViewFields style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">builder style="font-size: 16px;">. style="font-size: 16px;">addStatement style="font-size: 16px;">( style="font-size: 16px;">"host.$N=($T)finder.findView(source, $L)",

style="font-size: 16px;"> style="font-size: 16px;">field style="font-size: 16px;">. style="font-size: 16px;">getFieldName style="font-size: 16px;">(),

style="font-size: 16px;"> style="font-size: 16px;">ClassName style="font-size: 16px;">. style="font-size: 16px;">get style="font-size: 16px;">( style="font-size: 16px;">field style="font-size: 16px;">. style="font-size: 16px;">getFieldType style="font-size: 16px;">()),

style="font-size: 16px;"> style="font-size: 16px;">field style="font-size: 16px;">. style="font-size: 16px;">getViewId style="font-size: 16px;">());

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;">// 这里用来定义inject方法中@OnClick注解的绑定过程

style="font-size: 16px;"> style="font-size: 16px;">if style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">onClickMethods style="font-size: 16px;">. style="font-size: 16px;">size style="font-size: 16px;">()> 0 style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">builder style="font-size: 16px;">. style="font-size: 16px;">addStatement style="font-size: 16px;">("$T listener", style="font-size: 16px;"> style="font-size: 16px;">TypeUtils style="font-size: 16px;">. style="font-size: 16px;">ONCLICK_LISTENER style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">for style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">OnClickMethod style="font-size: 16px;">method: onClickMethods style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">TypeSpec style="font-size: 16px;">listener style="font-size: 16px;">= style="font-size: 16px;">TypeSpec style="font-size: 16px;">. style="font-size: 16px;">anonymousClassBuilder style="font-size: 16px;">( style="font-size: 16px;">"" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addSuperinterface style="font-size: 16px;">( style="font-size: 16px;">TypeUtils style="font-size: 16px;">. style="font-size: 16px;">ONCLICK_LISTENER style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addMethod style="font-size: 16px;">( style="font-size: 16px;">MethodSpec style="font-size: 16px;">. style="font-size: 16px;">methodBuilder style="font-size: 16px;">( style="font-size: 16px;">"onClick" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addAnnotation style="font-size: 16px;">( style="font-size: 16px;">Override style="font-size: 16px;">. style="font-size: 16px;">class style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addModifiers style="font-size: 16px;">( style="font-size: 16px;">Modifier style="font-size: 16px;">. style="font-size: 16px;">PUBLIC style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">returns style="font-size: 16px;">( style="font-size: 16px;">TypeName style="font-size: 16px;">. style="font-size: 16px;">VOID style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addParameter style="font-size: 16px;">( style="font-size: 16px;">TypeUtils style="font-size: 16px;">. style="font-size: 16px;">ANDROID_VIEW style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">"view" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addStatement style="font-size: 16px;">( style="font-size: 16px;">"host.$N()" style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">method style="font-size: 16px;">. style="font-size: 16px;">getMethodName style="font-size: 16px;">())

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">build style="font-size: 16px;">())

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">build style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">builder style="font-size: 16px;">. style="font-size: 16px;">addStatement style="font-size: 16px;">( style="font-size: 16px;">"listener = $L" style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">listener style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">for style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">int style="font-size: 16px;"> style="font-size: 16px;">id: method style="font-size: 16px;">. style="font-size: 16px;">getIds style="font-size: 16px;">()) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">builder style="font-size: 16px;">. style="font-size: 16px;">addStatement style="font-size: 16px;">( style="font-size: 16px;">"finder.findView(source, $L).setOnClickListener(listener)" style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">id style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;">//这里用来获取要生成的类所在的包的信息

style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">packageName style="font-size: 16px;">= style="font-size: 16px;">getPackageName style="font-size: 16px;">( style="font-size: 16px;">typeElement style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">className style="font-size: 16px;">= style="font-size: 16px;">getClassName style="font-size: 16px;">( style="font-size: 16px;">typeElement style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">packageName style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">ClassName style="font-size: 16px;">bindClassName style="font-size: 16px;">= style="font-size: 16px;">ClassName style="font-size: 16px;">. style="font-size: 16px;">get style="font-size: 16px;">( style="font-size: 16px;">packageName style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">className style="font-size: 16px;">);

style="font-size: 16px;">// 用来最终组装成我们要输出的类

style="font-size: 16px;"> style="font-size: 16px;">TypeSpec style="font-size: 16px;">finderClass style="font-size: 16px;">= style="font-size: 16px;">TypeSpec style="font-size: 16px;">. style="font-size: 16px;">classBuilder style="font-size: 16px;">( style="font-size: 16px;">bindClassName style="font-size: 16px;">. style="font-size: 16px;">simpleName style="font-size: 16px;">() "$ $Injector" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addModifiers style="font-size: 16px;">( style="font-size: 16px;">Modifier style="font-size: 16px;">. style="font-size: 16px;">PUBLIC style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addSuperinterface style="font-size: 16px;">( style="font-size: 16px;">ParameterizedTypeName style="font-size: 16px;">. style="font-size: 16px;">get style="font-size: 16px;">( style="font-size: 16px;">TypeUtils style="font-size: 16px;">. style="font-size: 16px;">INJECTOR style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">TypeName style="font-size: 16px;">. style="font-size: 16px;">get style="font-size: 16px;">( style="font-size: 16px;">typeElement style="font-size: 16px;">. style="font-size: 16px;">asType style="font-size: 16px;">())))

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">addMethod style="font-size: 16px;">( style="font-size: 16px;">builder style="font-size: 16px;">. style="font-size: 16px;">build style="font-size: 16px;">())

style="font-size: 16px;"> style="font-size: 16px;">. style="font-size: 16px;">build style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">return style="font-size: 16px;"> style="font-size: 16px;">JavaFile style="font-size: 16px;">. style="font-size: 16px;">builder style="font-size: 16px;">( style="font-size: 16px;">packageName style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">finderClass style="font-size: 16px;">). style="font-size: 16px;">build style="font-size: 16px;">();

}

三、注解是如何工作的?

注解仅仅是元数据,和业务逻辑无关,所以当你查看注解类时,发现里面没有任何逻辑处理,例如XUtils的ViewInject

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

    int value();

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

如果注解不包含业务逻辑处理,必然有人来实现这些逻辑。注解的逻辑实现是元数据的用户来处理的,注解仅仅提供它定义的属性(类/方法/变量/参数/包)的信息,注解的用户来读取这些信息并实现必要的逻辑。当使用java中的注解时(比如@Override、@Deprecated、@SuppressWarnings)JVM就是用户,它在字节码层面工作。如果是自定义的注解,比如第三方框架ActiveAndroid,它的用户是每个使用注解的类,所有使用注解的类都需要继承Model.java,在Model.java的构造方法中通过反射来获取注解类中的每个属性

 

2.2 基于 annotationProcessor 使用注解

6.3、 自定义 Annotation

自定义 Annotation 表示自己根据需要定义的 Annotation,定义时需要用到上面的元 Annotation
这里只是一种分类而已,也可以根据作用域分为源码时、编译时、运行时 Annotation

       通过上面这一段代码的初始化以后,在以后的运行中,你可以直接操作ORMConfig.Instance.[属性] 来访问你的属性,修改和保存的话继续用上面那一段代码就OK了。如果仅仅是读取配置文件的话,基本上可以脱离任何实现细节了。当然,初始化是必须的!!

OK,看完了程序的最终结果,我们来看一下如何生成上面的那个类文件。

七、如何自定义注解

首先,我们需要先了解注解处理器Processor,注解处理器有什么作用呢?首先它会在编译期被调用,可以扫描特定注解的信息,你可以为你自己的的注解注册处理器,一个特定的注解处理器以java源码作为输入,然后生成一些文件作(通常为java)为输出,这些java文件同样会被编译。这意味着,你可以根据注解的信息和被注解类的信息生成你想生成的代码!

需求:

定义一个注解MyAnnotation,去注解MainActivity,然后处理器扫描生成一个java文件,这个java文件有个输出Hello MyAnnotation的方法,运行的我们的MainAcitivity,然后调用这个java文件的方法。

至于GlobalInfo.MapPath()这个是一个能够适应在C/S模式与B/S模式下的一个路径计算方法。

  • @Documented 表示此注解将包含在 javadoc 中;
  • @Inherited 表示允许子类继承父类的注解;
  • @Repeatable 是 Java8 中新增的注解,表示指定的注解可以重复应用到指定的对象上面。

6.2、元 Annotation

@Retention, @Target, @Inherited, @Documented,元 Annotation 是指用来定义 Annotation 的 Annotation

style="font-size: 12pt;">不知道大家遇到烦人的配置文件读取与操作是怎么处理的呢?

特别说明:

  • 注解仅仅是元数据,和业务逻辑无关,所以当你查看注解类时,发现里面没有任何逻辑处理;
  • javadoc中的@author、@version、@param、@return、@deprecated、@hide、@throws、@exception、@see是文档注释标记,并不是注解;

下面,我们来实现一个基类

7.1、创建注解工程

同样我们先创建一个Java工程,编写一个注解类MyAnnotation

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    String value() default "MyAnnotation";
}

什么?还有不知道怎么使用? 我晕!!

@Retention

六、Annotation 分类

       可能很多很多人都在使用ConfigurationManage这个类来读取配置信息,这在按照需求要求的配置信息比较少的时候是一个非常好的方案。可是如果配置信息非常的多,而且是分好了类的配置信息 ,如果还使用ConfigurationManage就显得有点僵硬了。我们很多时候希望自己开发的逻辑组建化,并且可以对其进行管理,下面我就来提供一个方法来解决配置文件问题。

不过,首先我们还是先看一下一个基本的注解的定义的规范。下面我们自定义了一个名为 UseCase 的注解,可以看出我们用到了上面提及的几种元注解:

7.3、创建Compiler工程

AbstractProcessor

AbstractProcessor就是系统抽象出来的处理器类,如果我们要处理自己定义的注解,就必须借助于它。
例如:

public class MyProcessor extends AbstractProcessor{

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false;
    }

}

我们需要重写的方法有:

  • init(ProcessingEnvironment processingEnv) : 所有的注解处理器类都必须有一个无参构造函数。然而,有一个特殊的方法init(),它会被注解处理工具调用,以ProcessingEnvironment作为参数。ProcessingEnvironment 提供了一些实用的工具类Elements, Types和Filer。我们在后面将会使用到它们。

  • process(Set<? extends TypeElement> annoations, RoundEnvironment env) : 这类似于每个处理器的main()方法。你可以在这个方法里面编码实现扫描,处理注解,生成 java 文件。使用RoundEnvironment 参数,你可以查询被特定注解标注的元素。

  • getSupportedAnnotationTypes(): 在这个方法里面你必须指定哪些注解应该被注解处理器注册。注意,它的返回值是一个String集合,包含了你的注解处理器想要处理的注解类型的全称。换句话说,你在这里定义你的注解处理器要处理哪些注解。

  • getSupportedSourceVersion() : 用来指定你使用的 java 版本,建议使用SourceVersion.latestSupported()。

如果你的系统使用了依赖注入等技术的话,那恭喜你,你可以很方便的可以实现低耦合的Provider选择。如果你还对此没有了解的话可以关注一些依赖注入框架 例如spring.net等等    本人也实现了一个依赖注入,在以后的博文中将会陆续发布出来,如果你急于想了解的话可以联系我。

所以,比如根据上面的内容,我们可以直到我们的自定义注解 @UseCase 只能应用于方法和字段。

4.2、注解:

使用场合:

  • 动态配置信息;

  • 代为实现程序逻辑(比如xUtils中的@ViewInject代为实现findViewById);

  • 代码格式检查,比如Override、Deprecated、NonNull、StringRes等,便于IDE能够检查出代码错误;

优点:

  • 在class文件中,提高程序的内聚性;

  • 减少重复工作,提高开发效率,比如findViewById。

缺点:

  • 如果对annotation进行修改,需要重新编译整个工程;

  • 业务类之间的关系不如XML配置那样一目了然;

  • 程序中过多的annotation,对于代码的简洁度有一定影响;

  • 扩展性较差;

 

然后,我们使用Person类来获取该类的字段和方法的信息,并输出具有注解的部分:

6.2.3、@Documented

用于指定被修饰的Annotation将被javadoc工具提取成文档。即说明该注解将被包含在javadoc中。

如果是你自己开发的 Provider,那就你自己来开发这样的Attribute吧  实现起来也不麻烦。

我们之前已经讲过 bind() 方法的作用,即使用反射根据类名来获取一个 Injector ,然后调用它的 inject() 方法进行注入。这里的 Injector 是一个接口,我们不会写代码去实现它,而是在编译的时候让编译器直接生成它的实现类。

7.5、测试

新建一个Android工程,该工程依赖注解工程,至于compiler处理器工程,我们要使用apt的方式依赖。
这里有人要问了,apt是什么?

它主要有两个作用:

  • 能在编译时期去依赖注解处理器并进行工作,但在生成 APK 时不会包含任何遗留的东西
  • 能够辅助 Android Studio 在项目的对应目录中存放注解处理器在编译期间生成的文件

了解完apt,那我们就先在项目目录下的build.gradle中添加
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'这个依赖

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.1'
        // apt 
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

然后在Android 工程中,添加这个插件依赖

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

然后就可以使用apt依赖处理器工程了

apt project(':xs_compiler')

运行我们的Android工程,查看build生成文件

四川福彩快乐12app下载 9

Paste_Image.png

顺利生成我们的文件了,剩下就是怎么去调用这个sayHello的方法,我们的思路是通过反射生成的类,调用该方法。

在注解工程中,新建AnnotationApi类,编码如下

public class MyAnnotationApi {

    public static void sayHelloAnnotation(Object pTarget){
        String name = pTarget.getClass().getCanonicalName();
        try {
            Class clazz = Class.forName(name "$$HelloWorld");
            Method method = clazz.getMethod("sayHello");
            method.invoke(null);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}

然后在MainActivity中调用sayHelloAnnotation的方法

@MyAnnotation
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);
        MyAnnotationApi.sayHelloAnnotation(this);
    }

}

查看输出:

I/System.out: HelloMyAnnotation

完工!

四川福彩快乐12app下载 10四川福彩快乐12app下载 11 class="cnblogs_code_collapse" style="font-size: 12pt;">代码

  style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">class style="color: #000000; font-size: 12pt;"> ConfigService
    {
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">static style="color: #000000; font-size: 12pt;"> ConfigProvider provider {  style="color: #0000ff; font-size: 12pt;">get style="color: #000000; font-size: 12pt;">;  style="color: #0000ff; font-size: 12pt;">set style="color: #000000; font-size: 12pt;">; }

         style="color: #0000ff; font-size: 12pt;">static style="color: #000000; font-size: 12pt;"> ConfigService()
        {
style="color: #000000; font-size: 12pt;">            provider  style="color: #000000; font-size: 12pt;">= style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> XmlConfigProvider();
        }
         style="color: #0000ff; font-size: 12pt;">#region style="color: #000000; font-size: 12pt;"> Data Store style="color: #000000;">


         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">static style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> Load( style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> typename,  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> settings)
        {     
              style="color: #0000ff; font-size: 12pt;">return style="color: #000000; font-size: 12pt;"> provider.Load(typename, settings);    
        }

         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">static style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">void style="color: #000000; font-size: 12pt;"> Save( style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> typename,  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> settings)
        { 
style="color: #000000; font-size: 12pt;">            provider.Save(typename, settings);
        }


         style="color: #0000ff; font-size: 12pt;">#endregion style="color: #000000;">

    }

与 @Target 相同的是这个注解也使用枚举来指定值的类型,不同的是它只能指定一个值,具体可以看源码。这里它使用的是 RetentionPolicy 枚举,它的几个值的含义如下:

4.1 、配置文件:

使用场合:

  • 外部依赖的配置,比如build.gradle中的依赖配置;

  • 同一项目团队内部达成一致的时候;

  • 非代码类的资源文件(比如图片、布局、数据、签名文件等);

优点:

  • 降低耦合,配置集中,容易扩展,比如Android应用多语言支持;

  • 对象之间的关系一目了然,比如strings.xml;

  • xml配置文件比注解功能齐全,支持的类型更多,比如drawable、style等;

缺点:

  • 繁琐;

  • 类型不安全,比如R.java中的都是资源ID,用TextView的setText方法时传入int值时无法检测出该值是否为资源ID,但@StringRes可以;

我们可以基于这个Provider设计许多的实现类,具体怎么实现可以自己定制,比如说我希望把配置保存到数据库啊,我希望保存到XML文件啊,我希望保存为.txt文件啊 。 Provider没有提供具体的保存细节,这些细节你可以自己定制开发。我们这里的XmlConfigProvider就是序列化为xml后保存。当然如果这不符合你的系统要求,你可以自己实现具体的Provider

implementation project(':knife-api')

style="font-size: 16px;">implementation project style="font-size: 16px;">( style="font-size: 16px;">':knife-annotation' style="font-size: 16px;">)

style="font-size: 16px;">annotationProcessor project style="font-size: 16px;">( style="font-size: 16px;">':knife-compiler' style="font-size: 16px;">)

五、常用注解库

  • ButterKnife
  • Dagger2
  • Retrofit
  • EventBus
  • Afinal

    开源的Android的orm和ioc应用开发框架,其特点是小巧灵活,代码入侵量少。在android应用开发中,通过Afinal的ioc框架,诸如ui绑定,事件绑定,通过注解可以自动绑定。通过Afinal的orm框架,无需任何配置信息,一行代码就可以对android的sqlite数据库进行增删改查操作。同时,Afinal内嵌了finalHttp等简单易用的工具,可以轻松的对http就行求情的操作。

这个类就是对配置文件类进行简单的序列化之后,由 string Location(string typename)  提供保存地址然后进行保存的例子,在实现细节上大家可以多做修改。

  1. 首先,我们需要按照自己的需要考虑如何定义注解。
  2. 然后,我们需要实现 AbstractProcessor ,覆写各个方法,注册,并在 process 方法中完成生成类文件的操作。

四、注解和配置文件的区别

通过上面的描述可以发现,其实注解干的很多事情,通过配置文件也可以干,比如为类设置配置属性;但注解和配置文件是有很多区别的,在实际编程过程中,注解和配置文件配合使用在工作效率、低耦合、可拓展性方面才会达到权衡。

四川福彩快乐12app下载 12四川福彩快乐12app下载 13 class="cnblogs_code_collapse" style="font-size: 12pt;">代码

public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">class style="color: #000000; font-size: 12pt;"> ConfigBase style="color: #000000; font-size: 12pt;">< style="color: #000000; font-size: 12pt;">T style="color: #000000; font-size: 12pt;">> style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">where style="color: #000000; font-size: 12pt;"> T: style="color: #0000ff; font-size: 12pt;">class style="color: #000000;">
    {
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000; font-size: 12pt;"> T Load()
        {
             style="color: #0000ff; font-size: 12pt;">return style="color: #000000; font-size: 12pt;"> ConfigService.Load(GetTypeName(), style="color: #0000ff; font-size: 12pt;">this style="color: #000000; font-size: 12pt;">)  style="color: #0000ff; font-size: 12pt;">as style="color: #000000; font-size: 12pt;"> T;
        }
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">void style="color: #000000; font-size: 12pt;"> Save()
        {
style="color: #000000; font-size: 12pt;">            ConfigService.Save(GetTypeName(),  style="color: #0000ff; font-size: 12pt;">this style="color: #000000; font-size: 12pt;">);          
        }

         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> GetTypeName()
        {
             style="color: #0000ff; font-size: 12pt;">return style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">this style="color: #000000; font-size: 12pt;">.GetType().Name;
        }
    }

2.1 基于反射使用注解

6.2.4、@Inherited

用于指定被修饰的Annotation具有继承性。即子类可以继承父类中的该注解。比如:注解@TestAnnotation被元注解@Inherited修饰,把@TestAnnotation添加在类Base上,则Base的所有子类也将默认使用@TestAnnotation注解。

       大家注意到我们的上段代码中的异常信息是使用的AdminException,这个异常是一个自定义异常,是为了方便整个系统的管理而设计的。它表示这是一个可以显示异常信息给管理员查看的异常。

在我开始为我的开源项目马克笔记编写数据库的时候,我考虑了使用注解来为数据库对象指定字段的信息,并根据这心信息来拼接出创建数据库表的 SQL 语句。当时也想用反射来动态为每个字段赋值的,但是考虑到反射的性能比较差,最终放弃了这个方案。但是,使用注解处理的方式可以完美的解决我们的问题,即在编译的时候动态生成一堆代码,实际赋值的时候调用这些方法来完成。这前后两种方案就是我们今天要讲的注解的两种使用方式。

一、什么是注解?

注解对于开发人员来讲既熟悉又陌生,熟悉是因为只要你是做开发,都会用到注解(常见的@Override);陌生是因为即使不使用注解也照常能够进行开发;注解不是必须的,但了解注解有助于我们深入理解某些第三方框架(比如Android Support Annotations、ButterKnife、xUtils、ActiveAndroid等),提高工作效率。

Java注解又称为标注,是Java从1.5开始支持加入源码的特殊语法元数据;Java中的类、方法、变量、参数、包都可以被注解。这里提到的元数据是描述数据的数据,结合实例来说明:

<string name="app_name">AnnotationDemo</string>

这里的"app_name"就是描述数据"AnnotionDemo"的数据,这是在配置文件中写的,注解是在源码中写的,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_layout);
    new Thread(new Runnable(){
        @Override
        public void run(){
            setTextInOtherThread();
        }
    }).start();
}

在上面的代码中,在MainActivity.java中复写了父类Activity.java的onCreate方法,使用到了@Override注解。但即使不加上@Override注解标记代码,程序也能够正常运行。那这里的@Override注解有什么用呢?使用它有什么好处?事实上,@Override是告诉编译器这个方法是一个重写方法,如果父类中不存在该方法,编译器会报错,提示该方法不是父类中的方法。如果不小心拼写错误,将onCreate写成了onCreat,而且没有使用@Override注解,程序依然能够编译通过,但运行结果和期望的大不相同。而如果使用了@Override注解,拼写错误则会得到提示。从示例可以看出,注解有助于阅读代码。

使用注解很简单,根据注解类的@Target所修饰的对象范围,可以在类、方法、变量、参数、包中使用“@ 注解类名 [属性值]”的方式使用注解。比如:

@UiThread
private void setTextInOtherThread(@StringRes int resId){
    TextView threadTxtView = (TextView)MainActivity.this.findViewById(R.id.threadTxtViewId);
    threadTxtView.setText(resId);
}

至此,解决方案就出来了。从属性的保存,到读取,一条龙服务。方便吗?

上面的代码重点在于解析使用注解的类的信息,至于如何根据类信息生成类文件,我们还需要看下 AnnotatedClass 的 generateFinder() 方法,其代码如下所示。这里我们用了之前提到的 Javapoet 来帮助我们生成类文件:

6.2.1、@Retention(英文:保留)

用于指定被修饰的Annotation可以保留多长时间,只能修饰Annotation定义。

@Retention包含一个RetentionPolicy类型的value成员变量,使用@Retention必须为该value成员变量指定值。value成员变量的值有3个选择:

  • RetentionPolicy.CLASS: 编译器将把Annotation记录在class文件中。当运行java程序时,JVM不可获取Annotation信息。(默认值)
  • RetentionPolicy.RUNTIME: 编译器将把Annotation记录在class文件中。当运行java程序时,JVM也可获取Annotation信息,程序可以通过反射获取该Annotation信息
  • RetentionPolicy.SOURCE: Annotation只保留在源代码中(.java文件中),编译器直接丢弃这种Annotation。

比如:

//定义下面的MyAnnotaion保留到运行时,也可以使用value=RetentionPolicy.RUNTIME
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotaion{}

       以ORMConfig类为例子,我们这里使用的是XmlConfigProvider,所以如果你不想保存哪个属性就直接打上[XmlIgnore]就可以了

在定制之前,我们先看一下程序的最终执行结果,也许这样会更有助于理解整个过程的原理。我们程序的最终的执行结果是,在编译的时候,在使用我们的工具的类的相同级别的包下面生成一个类。如下图所示:

 

style="font-size: 16px;">publicstaticvoidbind(Objecthost,Objectsource,Finder finder){

style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">className style="font-size: 16px;">= style="font-size: 16px;">host style="font-size: 16px;">. style="font-size: 16px;">getClass style="font-size: 16px;">(). style="font-size: 16px;">getName style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">try style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">Injector style="font-size: 16px;">injector style="font-size: 16px;">= style="font-size: 16px;">FINDER_MAPPER style="font-size: 16px;">. style="font-size: 16px;">get style="font-size: 16px;">( style="font-size: 16px;">className style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">if style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">injector style="font-size: 16px;">== style="font-size: 16px;">null style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">Class style="font-size: 16px;">< style="font-size: 16px;">?> finderClass style="font-size: 16px;">= style="font-size: 16px;">Class style="font-size: 16px;">. style="font-size: 16px;">forName style="font-size: 16px;">( style="font-size: 16px;">className style="font-size: 16px;"> "$ $Injector");

style="font-size: 16px;"> style="font-size: 16px;">injector style="font-size: 16px;">= style="font-size: 16px;">( style="font-size: 16px;">Injector style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">finderClass style="font-size: 16px;">. style="font-size: 16px;">newInstance style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">FINDER_MAPPER style="font-size: 16px;">. style="font-size: 16px;">put style="font-size: 16px;">( style="font-size: 16px;">className style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">injector style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">injector style="font-size: 16px;">. style="font-size: 16px;">inject style="font-size: 16px;">( style="font-size: 16px;">host style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">source style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">finder style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">} style="font-size: 16px;"> style="font-size: 16px;">catch style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">ClassNotFoundException style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">. style="font-size: 16px;">printStackTrace style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">} style="font-size: 16px;"> style="font-size: 16px;">catch style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">IllegalAccessException style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">. style="font-size: 16px;">printStackTrace style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">} style="font-size: 16px;"> style="font-size: 16px;">catch style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">InstantiationException style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">. style="font-size: 16px;">printStackTrace style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">}

}

       

style="font-size: 16px;">annotationProcessor'com.jakewharton:butterknife-compiler:8.8.1'

        我自己在开发ORM的过程中也用到了这样的方法,具体信息请阅读轻量级ORM开发系列:缓存类信息以及配置文件的处理 一文

获取源码:Android-references 链接:)

         毫无疑问,这是一种紧耦合的方式,我们这里只是做一个例子,所以将就一下。

四川福彩快乐12app下载 14

object Load(string typename, object settings)   加载配置信息

 void Save(string typename, object settings)     保存配置信息

string Location(string typename)                       提供保存地址

 下面我们来看一个实现类

四川福彩快乐12app下载 15四川福彩快乐12app下载 16 class="cnblogs_code_collapse" style="font-size: 12pt;">代码

public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">class style="color: #000000; font-size: 12pt;"> XmlConfigProvider : ConfigProvider
    {
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">override style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> Load( style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> typename,  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> settings)
        {
             style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> _fileName  style="color: #000000; font-size: 12pt;">= style="color: #000000; font-size: 12pt;"> Location(typename);
             style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> returnobject  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">null style="color: #000000; font-size: 12pt;">;
             style="color: #0000ff; font-size: 12pt;">try style="color: #000000;">
            {
                 style="color: #0000ff; font-size: 12pt;">if style="color: #000000; font-size: 12pt;"> (File.Exists(_fileName))
style="color: #000000; font-size: 12pt;">                {
style="color: #000000; font-size: 12pt;">                    TextReader readertest  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> StreamReader(_fileName);
style="color: #000000; font-size: 12pt;">                    XmlSerializer x  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> XmlSerializer(settings.GetType());
style="color: #000000; font-size: 12pt;">                    returnobject  style="color: #000000; font-size: 12pt;">= style="color: #000000; font-size: 12pt;"> x.Deserialize(readertest);
style="color: #000000; font-size: 12pt;">                    readertest.Close();
style="color: #000000; font-size: 12pt;">                }
            }
             style="color: #0000ff; font-size: 12pt;">catch style="color: #000000; font-size: 12pt;"> (Exception e)
            {
                 style="color: #0000ff; font-size: 12pt;">throw style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> AdminException( style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">读取 style="color: #800000; font-size: 12pt;">" style="color: #000000; font-size: 12pt;"> style="color: #000000; font-size: 12pt;">typename style="color: #000000; font-size: 12pt;"> style="color: #000000; font-size: 12pt;">GlobalInfo.ConfigFileExtendName style="color: #000000; font-size: 12pt;"> style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">文件时发生了错误 style="color: #800000; font-size: 12pt;">" style="color: #000000; font-size: 12pt;">,e);
            }
             style="color: #0000ff; font-size: 12pt;">return style="color: #000000; font-size: 12pt;"> returnobject;
        }


         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">override style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">void style="color: #000000; font-size: 12pt;"> Save( style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> typename,  style="color: #0000ff; font-size: 12pt;">object style="color: #000000; font-size: 12pt;"> settings)
        {
             style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> _fileName  style="color: #000000; font-size: 12pt;">= style="color: #000000; font-size: 12pt;"> Location(typename);
             style="color: #0000ff; font-size: 12pt;">try style="color: #000000;">
            {
                 style="color: #0000ff; font-size: 12pt;">using style="color: #000000; font-size: 12pt;"> (TextWriter writer  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> StreamWriter(_fileName))
style="color: #000000; font-size: 12pt;">                {
style="color: #000000; font-size: 12pt;">                    XmlSerializer x  style="color: #000000; font-size: 12pt;">= style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> XmlSerializer(settings.GetType());
style="color: #000000; font-size: 12pt;">                    x.Serialize(writer, settings);
style="color: #000000; font-size: 12pt;">                    writer.Close();
style="color: #000000; font-size: 12pt;">                }

            }
             style="color: #0000ff; font-size: 12pt;">catch style="color: #000000; font-size: 12pt;"> (Exception e)
            {
                 style="color: #0000ff; font-size: 12pt;">throw style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">new style="color: #000000; font-size: 12pt;"> AdminException( style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">读取 style="color: #800000; font-size: 12pt;">" style="color: #000000;">  style="color: #000000; font-size: 12pt;"> style="color: #000000; font-size: 12pt;"> typename  style="color: #000000; font-size: 12pt;"> style="color: #000000; font-size: 12pt;"> GlobalInfo.ConfigFileExtendName  style="color: #000000; font-size: 12pt;"> style="color: #000000;">  style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">文件时发生了错误 style="color: #800000; font-size: 12pt;">" style="color: #000000; font-size: 12pt;">,e);
            }
        }
         style="color: #0000ff; font-size: 12pt;">public style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">override style="color: #000000;">  style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> Location( style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> typename)
        {
           
             style="color: #0000ff; font-size: 12pt;">string style="color: #000000; font-size: 12pt;"> ss style="color: #000000; font-size: 12pt;">= style="color: #000000; font-size: 12pt;"> GlobalInfo.MapPath( style="color: #800000; font-size: 12pt;">" style="color: #800000; font-size: 12pt;">Config/Common/ style="color: #800000; font-size: 12pt;">" style="color: #000000;">  style="color: #000000; font-size: 12pt;"> style="color: #000000; font-size: 12pt;"> typename  style="color: #000000; font-size: 12pt;"> style="color: #000000; font-size: 12pt;"> GlobalInfo.ConfigFileExtendName) ;
             style="color: #0000ff; font-size: 12pt;">return style="color: #000000; font-size: 12pt;"> ss;
        }
    }

这里为了演示基于反射的注解的使用方式,我们写一个小的 Java 程序,要实现的目的是:定义两个个注解,一个应用于方法,一个应用于字段,然后我们使用这两个注解来定义一个类。我们想要在代码中动态地打印出使用了注解的方法和字段的信息和注解信息。

  

代码的生成过程

这里只是提供了一个初稿,更加深入的,全面的还有待实现,这方面有兴趣的可以与我取得联系。 大家可以一起来探讨,实现一个强大的配置文件解决方案。抛砖引玉之作,不足之处,请海涵!

上面的代码的逻辑是,在调用 process() 方法的时候,会根据传入的 RoundEnvironment 分别处理两种注解。两个注解的相关信息都会被解析成 List 和 List ,然后把使用注解的整个类的信息统一放置在 AnnotatedClass 中。为了提升程序的效率,这里用了缓存来存储类信息。最后,我们调用了 annotatedClass.generateFinder() 获取一个JavaFile,并调用它的 writeTo(filer) 方法生成类文件。

     大家有任何的质疑和疑问都可以与我取得联系。

这里我们总结一下按照第二种方式使用注解的时候需要步骤:

     下面看我的例子

首先,我们需要定义注解用来提供给用户进行事件和控件的绑定,

这是一个普通的注解的定义。从上面我们也可以总结出,在定义注解的时候,有以下几个地方需要注意:

privateMap<String,AnnotatedClass> map= newHashMap<>();

style="font-size: 16px;">@ style="font-size: 16px;">Override

style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">boolean style="font-size: 16px;"> style="font-size: 16px;">process style="font-size: 16px;">( style="font-size: 16px;">Set style="font-size: 16px;">< style="font-size: 16px;">? style="font-size: 16px;"> style="font-size: 16px;">extends style="font-size: 16px;"> style="font-size: 16px;">TypeElement style="font-size: 16px;">> style="font-size: 16px;">set style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">RoundEnvironment style="font-size: 16px;">roundEnvironment style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">map style="font-size: 16px;">. style="font-size: 16px;">clear style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">try style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;">// 分别用来处理我们定义的两种注解

style="font-size: 16px;"> style="font-size: 16px;">processBindView style="font-size: 16px;">( style="font-size: 16px;">roundEnvironment style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">processOnClick style="font-size: 16px;">( style="font-size: 16px;">roundEnvironment style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">} style="font-size: 16px;"> style="font-size: 16px;">catch style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">IllegalArgumentException style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">return style="font-size: 16px;"> style="font-size: 16px;">true style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">try style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;">// 为缓存的各个使用注解的类生成类文件

style="font-size: 16px;"> style="font-size: 16px;">for style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">AnnotatedClass style="font-size: 16px;">annotatedClass style="font-size: 16px;">: style="font-size: 16px;">map style="font-size: 16px;">. style="font-size: 16px;">values style="font-size: 16px;">()) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">annotatedClass style="font-size: 16px;">. style="font-size: 16px;">generateFinder style="font-size: 16px;">(). style="font-size: 16px;">writeTo style="font-size: 16px;">( style="font-size: 16px;">filer style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">} style="font-size: 16px;"> style="font-size: 16px;">catch style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">Exception style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">. style="font-size: 16px;">printStackTrace style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">return style="font-size: 16px;"> style="font-size: 16px;">true style="font-size: 16px;">;

}

// 从RoundEnvironment中获取@BindView注解的信息

style="font-size: 16px;">private style="font-size: 16px;"> style="font-size: 16px;">void style="font-size: 16px;"> style="font-size: 16px;">processBindView style="font-size: 16px;">( style="font-size: 16px;">RoundEnvironment style="font-size: 16px;">roundEnv style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">for style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">Element style="font-size: 16px;">element style="font-size: 16px;">: style="font-size: 16px;">roundEnv style="font-size: 16px;">. style="font-size: 16px;">getElementsAnnotatedWith style="font-size: 16px;">( style="font-size: 16px;">BindView style="font-size: 16px;">. style="font-size: 16px;">class style="font-size: 16px;">)) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">AnnotatedClass style="font-size: 16px;">annotatedClass style="font-size: 16px;">= style="font-size: 16px;">getAnnotatedClass style="font-size: 16px;">( style="font-size: 16px;">element style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">BindViewField style="font-size: 16px;">field= new style="font-size: 16px;"> style="font-size: 16px;">BindViewField style="font-size: 16px;">( style="font-size: 16px;">element style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">annotatedClass style="font-size: 16px;">. style="font-size: 16px;">addField style="font-size: 16px;">( style="font-size: 16px;">field style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

}

// 从RoundEnvironment中获取@OnClick注解的信息

style="font-size: 16px;">private style="font-size: 16px;"> style="font-size: 16px;">void style="font-size: 16px;"> style="font-size: 16px;">processOnClick style="font-size: 16px;">( style="font-size: 16px;">RoundEnvironment style="font-size: 16px;">roundEnv style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">for style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">Element style="font-size: 16px;">element style="font-size: 16px;">: style="font-size: 16px;">roundEnv style="font-size: 16px;">. style="font-size: 16px;">getElementsAnnotatedWith style="font-size: 16px;">( style="font-size: 16px;">OnClick style="font-size: 16px;">. style="font-size: 16px;">class style="font-size: 16px;">)) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">AnnotatedClass style="font-size: 16px;">annotatedClass style="font-size: 16px;">= style="font-size: 16px;">getAnnotatedClass style="font-size: 16px;">( style="font-size: 16px;">element style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">OnClickMethod style="font-size: 16px;">method= new style="font-size: 16px;"> style="font-size: 16px;">OnClickMethod style="font-size: 16px;">( style="font-size: 16px;">element style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">annotatedClass style="font-size: 16px;">. style="font-size: 16px;">addMethod style="font-size: 16px;">( style="font-size: 16px;">method style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

}

// 获取使用注解的类的信息,先尝试从缓存中获取,缓存中没有的话就实例化一个并放进缓存中

style="font-size: 16px;">private style="font-size: 16px;"> style="font-size: 16px;">AnnotatedClass getAnnotatedClass style="font-size: 16px;">( style="font-size: 16px;">Element style="font-size: 16px;">element style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">TypeElement style="font-size: 16px;">encloseElement style="font-size: 16px;">= style="font-size: 16px;">( style="font-size: 16px;">TypeElement style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">element style="font-size: 16px;">. style="font-size: 16px;">getEnclosingElement style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">fullClassName style="font-size: 16px;">= style="font-size: 16px;">encloseElement style="font-size: 16px;">. style="font-size: 16px;">getQualifiedName style="font-size: 16px;">(). style="font-size: 16px;">toString style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">AnnotatedClass style="font-size: 16px;">annotatedClass style="font-size: 16px;">= style="font-size: 16px;">map style="font-size: 16px;">. style="font-size: 16px;">get style="font-size: 16px;">( style="font-size: 16px;">fullClassName style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">if style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">annotatedClass style="font-size: 16px;">== style="font-size: 16px;">null style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">annotatedClass style="font-size: 16px;">= style="font-size: 16px;">new style="font-size: 16px;"> style="font-size: 16px;">AnnotatedClass style="font-size: 16px;">( style="font-size: 16px;">encloseElement style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">elements style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">map style="font-size: 16px;">. style="font-size: 16px;">put style="font-size: 16px;">( style="font-size: 16px;">fullClassName style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">annotatedClass style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">return style="font-size: 16px;"> style="font-size: 16px;">annotatedClass style="font-size: 16px;">;

}

2、注解的两种使用方式

另一个我们需要特别说明的地方是,继承 AbstractProcessor 并实现了我们自己的处理器之后还要对它进行注册才能使用。一种做法是在与 java 相同的目录下面创建一个 resources 文件夹,并在其中创建 META-INF/service 文件夹,然后在其中创建一个名为 javax.annotation.processing.Processor 的文件,并在其中写上我们的处理器的完整路径。另一种做法是使用谷歌的 @AutoService 注解,你只需要在自己的处理器上面加上 @AutoService(Processor.class) 一行代码即可。当然,前提是你需要在自己的项目中引入依赖:

上面的代码可以解决一些问题,但同时,我们还有一些地方需要注意:

这里的 me.shouheng.libraries 是我们应用 MyKnife 的包,这里我们在它下面生成了一个名为 MyKnifeActivity$ $Injector 的类,它的定义如下:

@Documented

style="font-size: 16px;">@ style="font-size: 16px;">Retention style="font-size: 16px;">( style="font-size: 16px;">RetentionPolicy style="font-size: 16px;">. style="font-size: 16px;">RUNTIME style="font-size: 16px;">)

style="font-size: 16px;">@ style="font-size: 16px;">Target style="font-size: 16px;">( style="font-size: 16px;">value style="font-size: 16px;">= style="font-size: 16px;">{ style="font-size: 16px;">METHOD style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">FIELD style="font-size: 16px;">})

public @ style="font-size: 16px;">interface style="font-size: 16px;"> style="font-size: 16px;">UseCase style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">int style="font-size: 16px;"> style="font-size: 16px;">id style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">deion style="font-size: 16px;">() style="font-size: 16px;"> style="font-size: 16px;">default style="font-size: 16px;"> style="font-size: 16px;">"default value" style="font-size: 16px;">;

}

style="font-size: 16px;">publicclassMyKnifeActivityextendsCommonActivity<ActivityMyKnifeBinding> {

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">BindView style="font-size: 16px;">( style="font-size: 16px;">id= R style="font-size: 16px;">. style="font-size: 16px;">id style="font-size: 16px;">. style="font-size: 16px;">tv style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">TextView style="font-size: 16px;">textView style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">OnClick style="font-size: 16px;">( style="font-size: 16px;">ids= { style="font-size: 16px;">R style="font-size: 16px;">. style="font-size: 16px;">id style="font-size: 16px;">. style="font-size: 16px;">btn style="font-size: 16px;">})

style="font-size: 16px;"> style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">void style="font-size: 16px;"> style="font-size: 16px;">OnClick style="font-size: 16px;">() style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">ToastUtils style="font-size: 16px;">. style="font-size: 16px;">makeToast style="font-size: 16px;">( style="font-size: 16px;">"OnClick" style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">Override

style="font-size: 16px;"> style="font-size: 16px;">protected style="font-size: 16px;"> style="font-size: 16px;">int style="font-size: 16px;"> style="font-size: 16px;">getLayoutResId style="font-size: 16px;">() style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">return style="font-size: 16px;"> style="font-size: 16px;">R style="font-size: 16px;">. style="font-size: 16px;">layout style="font-size: 16px;">. style="font-size: 16px;">activity_my_knife style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">Override

style="font-size: 16px;"> style="font-size: 16px;">protected style="font-size: 16px;"> style="font-size: 16px;">void style="font-size: 16px;"> style="font-size: 16px;">doCreateView style="font-size: 16px;">(Bundle savedInstanceState style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">MyKnife style="font-size: 16px;">. style="font-size: 16px;">bind style="font-size: 16px;">( style="font-size: 16px;">this style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">textView style="font-size: 16px;">. style="font-size: 16px;">setText style="font-size: 16px;">("This is MyKnife demo!" style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

}

原标题:Java 注解及其在 Android 中的应用

@Override

style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">synchronized style="font-size: 16px;">void style="font-size: 16px;"> style="font-size: 16px;">init style="font-size: 16px;">( style="font-size: 16px;">ProcessingEnvironment style="font-size: 16px;">processingEnvironment style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">super style="font-size: 16px;">. style="font-size: 16px;">init style="font-size: 16px;">( style="font-size: 16px;">processingEnvironment style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">elements style="font-size: 16px;">= style="font-size: 16px;">processingEnvironment style="font-size: 16px;">. style="font-size: 16px;">getElementUtils style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">messager style="font-size: 16px;">= style="font-size: 16px;">processingEnvironment style="font-size: 16px;">. style="font-size: 16px;">getMessager style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">filer= style="font-size: 16px;">processingEnvironment style="font-size: 16px;">. style="font-size: 16px;">getFiler style="font-size: 16px;">();

}

  • SOURCE:注解将被编译器丢弃
  • CLASS:注解在class文件中使用,但会被JVM丢弃
  • RUNTIME:VM将在运行期保留注解,故可以通过反射读取注解的信息

这里我们先定义两个注解,应用于字段的 @Column 注解和应用于方法 @Important 注解:

在上面的代码的执行结果,我们可以看出:使用了注解和反射之后,我们成功的打印出了使用了注解的字段。这里我们需要先获取指定的类的 Class 类型,然后用反射获取它的所有方法和字段信息并进行遍历,通过判断它们的 getAnnotation() 方法的结果来确定这个方法和字段是否使用了指定类型的注解。

@Target 用来指定注解能够修饰的对象的类型。因为 @Target 本身也是一个注解,所以你可以在源码中查看它的定义。该注解接收的参数是一个 ElementType 类型的数组,所以,就是说我们自定义的注解可以应用到多种类型的对象,而对象的类型由 ElementType 定义。 ElementType 是一个枚举,它的枚举值如下:

API 和注解的定义

这几个方法中,除了 process ,其他方法都不是必须覆写的方法。这里的 getSupportedAnnotationTypes 和 getSupportedSourceVersion 可以使用注 @SupportedAnnotationTypes 和 @SupportedSourceVersion 来替换,但是不建议这么做。因为前面的注解接收的参数是字符串,如果你使用了混淆可能就比较麻烦,后面的注解只能使用枚举,相对欠缺了灵活性。

总结

style="font-size: 16px;">publicstaticvoidbind(Objecthost,Objectsource,Finder finder){

style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">className style="font-size: 16px;">= style="font-size: 16px;">host style="font-size: 16px;">. style="font-size: 16px;">getClass style="font-size: 16px;">(). style="font-size: 16px;">getName style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">try style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">Injector style="font-size: 16px;">injector style="font-size: 16px;">= style="font-size: 16px;">FINDER_MAPPER style="font-size: 16px;">. style="font-size: 16px;">get style="font-size: 16px;">( style="font-size: 16px;">className style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">if style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">injector style="font-size: 16px;">== style="font-size: 16px;">null style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">Class style="font-size: 16px;">< style="font-size: 16px;">?> finderClass style="font-size: 16px;">= style="font-size: 16px;">Class style="font-size: 16px;">. style="font-size: 16px;">forName style="font-size: 16px;">( style="font-size: 16px;">className style="font-size: 16px;"> "$ $Injector");

style="font-size: 16px;"> style="font-size: 16px;">injector style="font-size: 16px;">= style="font-size: 16px;">( style="font-size: 16px;">Injector style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">finderClass style="font-size: 16px;">. style="font-size: 16px;">newInstance style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">FINDER_MAPPER style="font-size: 16px;">. style="font-size: 16px;">put style="font-size: 16px;">( style="font-size: 16px;">className style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">injector style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">injector style="font-size: 16px;">. style="font-size: 16px;">inject style="font-size: 16px;">( style="font-size: 16px;">host style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">source style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">finder style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">} style="font-size: 16px;"> style="font-size: 16px;">catch style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">ClassNotFoundException style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">. style="font-size: 16px;">printStackTrace style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">} style="font-size: 16px;"> style="font-size: 16px;">catch style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">IllegalAccessException style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">. style="font-size: 16px;">printStackTrace style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">} style="font-size: 16px;"> style="font-size: 16px;">catch style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">InstantiationException style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">e style="font-size: 16px;">. style="font-size: 16px;">printStackTrace style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">}

}

  1. 使用 @interface 声明并且指定注解的名称;
  2. 注解的定义类似于接口中的方法的定义,但要注意两者之间本质上是不同的;
  3. 可以通过 default 为指定的元素指定一个默认值,如果用户没有为其指定值,就使用默认值。

@Target(ElementType.FIELD)

style="font-size: 16px;">@ style="font-size: 16px;">Retention style="font-size: 16px;">( style="font-size: 16px;">RetentionPolicy style="font-size: 16px;">. style="font-size: 16px;">CLASS style="font-size: 16px;">)

style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">interface style="font-size: 16px;"> style="font-size: 16px;">BindView style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">int style="font-size: 16px;"> style="font-size: 16px;">id style="font-size: 16px;">();

}

style="font-size: 16px;">@ style="font-size: 16px;">Target style="font-size: 16px;">( style="font-size: 16px;">ElementType style="font-size: 16px;">. style="font-size: 16px;">METHOD style="font-size: 16px;">)

style="font-size: 16px;">@ style="font-size: 16px;">Retention style="font-size: 16px;">( style="font-size: 16px;">RetentionPolicy style="font-size: 16px;">. style="font-size: 16px;">CLASS style="font-size: 16px;">)

style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">interface style="font-size: 16px;">OnClick style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">int style="font-size: 16px;">[] style="font-size: 16px;"> style="font-size: 16px;">ids style="font-size: 16px;">();

}

上文,我们回顾了 Java 中注解相关的知识点,相信你已经对注解的内容有了一些了解,那么我们接下来看一下注解在实际开发中的两种应用方式。

然后,我们需要定义 MyKnife ,它提供了一个 bind() 方法,其定义如下:

也许你之前已经使用过 ButterKnife 这样的注入框架,不知道你是否记得在 Gradle 中引用它的时候加入了下面这行依赖:

  1. 使用注解的方法和字段需要至少是 protected ,因为我们使用了直接引用的方式,而生成的文件和上面的类包相同,所以至少应该保证包级别访问权限;
  2. 上面使用注解的方式只能在当前 Module 作为 application 的时候使用,作为 library 的时候无法使用,这是因为只有当 Module 作为 application 的时候,R文件中的 id 是 final 的,作为 library 的时候是非 final 的。

MyKnife 的最终结果

style="font-size: 16px;">compile'com.google.auto.service:auto-service:1.0-rc2'

1、Java 注解回顾1. Java 注解的基础知识

也许你在有的地方看到过要使用 android-apt 引入注解处理器,其实这里的 annotationProcessor 与之作用是一样的。这里推荐使用 annotationProcessor ,因为它更加简洁,不需要额外的配置,也是官方推荐的使用方式。

一般的,注解在 Android 中有两种应用方式,一种方式是基于反射的,即在程序的运行期间获取类信息进行反射调用;另一种是使用注解处理,在编译期间生成许多代码,然后在运行期间通过调用这些代码来实现目标功能。

然后,我们只需要在代码中使用它们就可以了:

当我们在 Android 中使用注解的时候,一种是在运行时使用的,所以我们要用 RUNTIME ;另一种是在编译时使用的,所以我们用 CLASS 。

@Documented、@Inherited 和 @Repeatable

这里的 AbstractProcessor 是用来生成类文件的核心类,它是一个抽象类,一般使用的时候我们只要覆写它的方法中的4个就可以了。下面是这些方法及其定义:

这样我们就完成了整个方法的定义。

@Target(value= {ElementType.FIELD})

style="font-size: 16px;">@ style="font-size: 16px;">Retention style="font-size: 16px;">( style="font-size: 16px;">RetentionPolicy style="font-size: 16px;">. style="font-size: 16px;">RUNTIME style="font-size: 16px;">)

style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">interface style="font-size: 16px;">Column style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">name style="font-size: 16px;">();

}

style="font-size: 16px;">@ style="font-size: 16px;">Target style="font-size: 16px;">( style="font-size: 16px;">value= { style="font-size: 16px;">ElementType style="font-size: 16px;">. style="font-size: 16px;">METHOD style="font-size: 16px;">})

style="font-size: 16px;">@ style="font-size: 16px;">Retention style="font-size: 16px;">( style="font-size: 16px;">RetentionPolicy style="font-size: 16px;">. style="font-size: 16px;">RUNTIME style="font-size: 16px;">)

style="font-size: 16px;">public style="font-size: 16px;">< style="font-size: 16px;">a style="font-size: 16px;"> style="font-size: 16px;">href style="font-size: 16px;">= style="font-size: 16px;">"" style="font-size: 16px;">> style="font-size: 16px;">@ style="font-size: 16px;">interface style="font-size: 16px;"></ style="font-size: 16px;">a> WrappedMethod style="font-size: 16px;"> style="font-size: 16px;">{

}

按照后面的这种方式一样会在目录下面生成上面的那个文件,只是这个过程不需要我们来操作了。你可以通过查看buidl出的文件来找到生成的文件。

Java 中的注解分成标准注解和元注解。标准注解是 Java 为我们提供的预定义的注解,共有四种: @Override、 @Deprecated 、 @SuppressWarnnings 和 @SafeVarags 。元注解是用来提供给用户自定义注解用的,共有五种(截止到Java8): @Target 、 @Retention 、 @Documented 、 @Inherited 和 @Repeatable ,这里我们重点介绍这五种元注解。

使用我们定义的 MyKnife ,我们只需要在 Gradle 里面引入我们的包即可:

上面就是我们用来最终生成类文件的方法,这里用了 Javapoet ,如果对它不是很了解可以到 Github 上面了解一下它的用法。

在介绍 Javapoet 和 AbstractProcessor 的时候,我们提到过 Element,它封装了应用注解的对象(方法、字段或者类等)的信息。我们可以从 Element 中获取这些信息并将它们封装成一个对象来方便我们调用。于是就产生了 BindViewField 和 OnClickMethod 两个类。它们分别用来描述使用 @BindView 注解和使用 @OnClick 注解的对象的信息。此外,还有一个 AnnotatedClass ,它用来描述使用注解的整个类的信息,并且其中定义了 List 和 List ,分别用来存储该类中应用注解的字段和方法的信息。

style="font-size: 16px;">publicclassMyKnifeActivity$$InjectorimplementsInjector<MyKnifeActivity> {

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">Override

style="font-size: 16px;"> style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">void style="font-size: 16px;"> style="font-size: 16px;">inject style="font-size: 16px;">( style="font-size: 16px;">final style="font-size: 16px;"> style="font-size: 16px;">MyKnifeActivity style="font-size: 16px;">host style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">Object style="font-size: 16px;"> style="font-size: 16px;">source style="font-size: 16px;">, style="font-size: 16px;">Finder finder style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">host style="font-size: 16px;">. style="font-size: 16px;">textView style="font-size: 16px;">= style="font-size: 16px;">( style="font-size: 16px;">TextView style="font-size: 16px;">) style="font-size: 16px;">finder style="font-size: 16px;">. style="font-size: 16px;">findView style="font-size: 16px;">( style="font-size: 16px;">source style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">2131230952 style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">View style="font-size: 16px;">. style="font-size: 16px;">OnClickListener style="font-size: 16px;">listener style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">listener style="font-size: 16px;">= style="font-size: 16px;">new style="font-size: 16px;"> style="font-size: 16px;">View style="font-size: 16px;">. style="font-size: 16px;">OnClickListener style="font-size: 16px;">() style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">Override

style="font-size: 16px;"> style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">void style="font-size: 16px;"> style="font-size: 16px;">onClick style="font-size: 16px;">(View view style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">host style="font-size: 16px;">. style="font-size: 16px;">OnClick style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">};

style="font-size: 16px;"> style="font-size: 16px;">finder style="font-size: 16px;">. style="font-size: 16px;">findView style="font-size: 16px;">( style="font-size: 16px;">source style="font-size: 16px;">, style="font-size: 16px;"> style="font-size: 16px;">2131230762 style="font-size: 16px;">). style="font-size: 16px;">setOnClickListener style="font-size: 16px;">( style="font-size: 16px;">listener style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

}

以上就是注解的两种比较常见的使用方式。第一种是通过反射来进行的,因为反射本身的效率比较低,所以比较适用于发射比较少的场景;第二种方式是在编译期间通过编译器生成代码来实现的,相比于第一种,它还是可能会用到反射的,但是不必在运行时对类的每个方法和字段进行遍历,因而效率高得多。

好的,看完了一个基本的注解的定义,我们来看一下上面用到的 Java 元注解的含义。

  1. init :在生成代码之前被调用,可以从它参数 ProcessingEnvironment 获取到非常多有用的工具类;
  2. process :用于生成代码的 Java 方法,可以从参数 RoundEnvironment 中获取使用指定的注解的对象的信息,并包装成一个 Element 类型返回;
  3. getSupportedAnnotationTypes :用于指定该处理器适用的注解;
  4. getSupportedSourceVersion :用来指定你使用的 Java 的版本。

这里的 annotationProcessor 就是我们这里要讲的注解处理。本质上它会在编译的时候,在你调用 ButterKnife.bind(this); 方法的那个类所在的包下面生成一些类,当调用 ButterKnife.bind(this); 的时候实际上就完成了为使用注解的方法和控件绑定的过程。也就是,本质上还是调用了 findViewById() ,只是这个过程被隐藏了,不用你来完成了,仅此而已。

责任编辑:

3、总结

这里的三个参数的含义分别是: host 是调用绑定方法的类,比如 Activity 等; source 是从用来获取绑定的值的数据源,一般理解是从 source 中获取控件赋值给 host 中的字段,通常两者是相同的;最后一个参数 finder 是一个接口,是获取数据的方法的一个封装,有两默认的实现,一个是 ActivityFinder ,一个是 ViewFinder ,分别用来从 Activity 和 View 中查找控件。

style="font-size: 16px;">publicstaticvoidmain(String...args){

style="font-size: 16px;"> style="font-size: 16px;">Class style="font-size: 16px;">< style="font-size: 16px;">?> c style="font-size: 16px;">= style="font-size: 16px;">Person style="font-size: 16px;">. style="font-size: 16px;">class style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">Method style="font-size: 16px;">[] style="font-size: 16px;"> style="font-size: 16px;">methods style="font-size: 16px;">= style="font-size: 16px;">c style="font-size: 16px;">. style="font-size: 16px;">getDeclaredMethods style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">for style="font-size: 16px;"> style="font-size: 16px;">(Method method style="font-size: 16px;">: style="font-size: 16px;">methods style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">if style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">method style="font-size: 16px;">. style="font-size: 16px;">getAnnotation style="font-size: 16px;">( style="font-size: 16px;">WrappedMethod style="font-size: 16px;">. style="font-size: 16px;">class style="font-size: 16px;">)!= null style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">System style="font-size: 16px;">. style="font-size: 16px;">out style="font-size: 16px;">. style="font-size: 16px;">print style="font-size: 16px;">( style="font-size: 16px;">method style="font-size: 16px;">. style="font-size: 16px;">getName style="font-size: 16px;">() " " style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">System style="font-size: 16px;">. style="font-size: 16px;">out style="font-size: 16px;">. style="font-size: 16px;">println style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">Field style="font-size: 16px;">[] style="font-size: 16px;"> style="font-size: 16px;">fields= c style="font-size: 16px;">. style="font-size: 16px;">getDeclaredFields style="font-size: 16px;">();

style="font-size: 16px;"> style="font-size: 16px;">for style="font-size: 16px;"> style="font-size: 16px;">(Field field style="font-size: 16px;">: style="font-size: 16px;">fields style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;">Column column style="font-size: 16px;">= style="font-size: 16px;">field style="font-size: 16px;">. style="font-size: 16px;">getAnnotation style="font-size: 16px;">( style="font-size: 16px;">Column style="font-size: 16px;">. style="font-size: 16px;">class style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">if style="font-size: 16px;"> style="font-size: 16px;">( style="font-size: 16px;">column style="font-size: 16px;">!= style="font-size: 16px;">null style="font-size: 16px;">) style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">System style="font-size: 16px;">. style="font-size: 16px;">out style="font-size: 16px;">. style="font-size: 16px;">print style="font-size: 16px;">( style="font-size: 16px;">column style="font-size: 16px;">. style="font-size: 16px;">name style="font-size: 16px;">() "-" style="font-size: 16px;"> style="font-size: 16px;">field style="font-size: 16px;">. style="font-size: 16px;">getName style="font-size: 16px;">() ", " style="font-size: 16px;">);

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">}

}

2. 元注解

  1. 如果指定的方法或者字段名被混淆了怎么办? 对于一些可以自定义名称的情景,我们可以在注解中加入参数为该字段或者方法指定一个名称;
  2. 上面使用了很多的反射,这会影响程序的性能吗? 使用注解的方式肯定性能不会高,但是如果注解的使用没有那么频繁,上面方法不会有特别大的性能损耗,比如拼接 SQL 这样的操作,可能只需要执行一次。不过,根本的解决办法是使用注解的第二种使用方式!

使用 MyKnife

输出结果:

然后在 AbstractProcessor 的 process() 方法中的 RoundEnvironment 参数中,我们又可以获取到指定注解对应的 Element 信息。代码如下所示:

如上面的代码所示,可以看出我们分别用了 ElementType.FIELD 和 ElementType.METHOD 指定它们是应用于字段和方法的,然后用了 RetentionPolicy.CLASS 标明它们不会被保留到程序运行时。

@Target

从上面的代码中可以看出,调用 bind() 方法的时候会从 FINDER_MAPPER 尝试获取指定 类名$ $Injector 的文件。所以,如果说我们应用 bind() 的类是 MyKnifeActivity ,那么这里获取到的类将会是 MyKnifeActivity$ $Injector 。然后,当我们调用 inject 方法的时候就执行了我们上面的注入操作,来完成对控件和点击事件的赋值。这里的 FINDER_MAPPER 是一个哈希表,用来缓存指定的 Injector 的。所以,从上面也可以看出,这里进行值绑定的时候使用了反射,所以,在应用框架的时候还需要对混淆进行处理。

然后我们定义了一个Person类,并使用注解为其中的部分方法和字段添加注解:

下面,我们就使用注解处理的功能来制作一个类似于 ButterKnife 的简单库。不过,在那之前我们还需要做一些准备——一些知识点需要进行说明。即Javapoet和 AbstractProcessor 。

这里有几个地方需要注意:

  • TYPE:类、接口或者enum声明
  • FIELD:域声明,包括enum实例
  • METHOD:方法声明
  • PARAMETER:参数声明
  • CONSTRUCTOR:构造器声明
  • LOCAL_VARIABLE:局部变量声明
  • ANNOTATION_TYPE:注解声明
  • PACKAGE:包声明
  • TYPE_PARAMETER:类型参数声明
  • TYPE_USE:使用类型

这三个元注解的功能比较简单和容易理解,这里我们一起给出即可:

来源:WngShhng

style="font-size: 16px;">

privatestaticclassPerson{

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">Column style="font-size: 16px;">( style="font-size: 16px;">name= "id" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">private style="font-size: 16px;"> style="font-size: 16px;">int style="font-size: 16px;"> style="font-size: 16px;">id style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">Column style="font-size: 16px;">( style="font-size: 16px;">name= "first_name" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">private style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">firstName style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">Column style="font-size: 16px;">( style="font-size: 16px;">name= "last_name" style="font-size: 16px;">)

style="font-size: 16px;"> style="font-size: 16px;">private style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">lastName style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">private style="font-size: 16px;"> style="font-size: 16px;">int style="font-size: 16px;"> style="font-size: 16px;">temp style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">@ style="font-size: 16px;">WrappedMethod style="font-size: 16px;">()

style="font-size: 16px;"> style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">getInfo style="font-size: 16px;">() style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">return style="font-size: 16px;"> style="font-size: 16px;">id " :" style="font-size: 16px;"> style="font-size: 16px;">firstName style="font-size: 16px;"> " " style="font-size: 16px;">lastName style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">}

style="font-size: 16px;"> style="font-size: 16px;">public style="font-size: 16px;"> style="font-size: 16px;">String style="font-size: 16px;"> style="font-size: 16px;">method style="font-size: 16px;">() style="font-size: 16px;"> style="font-size: 16px;">{

style="font-size: 16px;"> style="font-size: 16px;">return style="font-size: 16px;"> style="font-size: 16px;">"Nothing" style="font-size: 16px;">;

style="font-size: 16px;"> style="font-size: 16px;">}

}

在本篇文章中,我们会先重温一下 Java 的注解相关的知识,然后分别介绍一下上面两种方式的实际应用。

Javapoet & AbstractProcessor

与生成文件和获取注解的对象信息相关的几个字段都是从 AbstractProcessor 中获取的。如下面的代码所示,我们可以从 AbstractProcessor 的 init() 方法的 ProcessingEnvironment 中获取到 Elements 、 Filer 和 Messager 。它们的作用分别是: Elements 类似于一个工具类,用来从 Element 中获取注解对象的信息; Filer 用来支持通过注释处理器创建新文件; Messager 提供注释处理器用来报告错误消息、警告和其他通知的方式。

本文由四川福彩快乐12app下载发布于科学技术,转载请注明出处:抛弃ConfigurationManager , 实现面向对象读写配置文件

关键词: 开发 AR Android Android... An