Android开发技巧之使用自定义注解

前言

 一些优秀的开源框架如比较早的xUtils网络加载框架及现在最新版本的greenDao 3.X ORM框架支持注解,注解的使用可以使得我们的代码架构变得更加清晰,同时也更能体现出面向对象语言的继承的魅力。我们在Android开发过程中可以使用注解来优化我们的代码结构。

Java注解简介

注解Annotation其实是一种元数据,不包含业务逻辑,它的作用是用来给类,接口,域等提供数据。jdk5.0定义了如下四种元注解(用来标识注解的)

  1. @Target:用来标识注解作用范围,其取值可以有:
    • CONSTRUCTOR:用于描述构造器
    • FIELD:用于描述域
    • LOCAL_VARIABLE:用于描述局部变量
    • METHOD:用于描述方法
    • PACKAGE:用于描述包
    • PARAMETER:用于描述参数
    • TYPE:用于描述类、接口(包括注解类型) 或enum声明
  2. @Retention:用来标识注解的生命周期,即什么时候有效,其取值如下:
    1. SOURCE:在源文件中有效(即源文件保留)
    2. CLASS:在class文件中有效(即class保留)
    3. RUNTIME:在运行时有效(即运行时保留)
  3. @Inherited:表明该注解是否可以被子类所继承,即如果使用一个Inherited标识的注解作用的类被其子类所继承,那么其子类也被该注解所标识。
  4. @Documented:标记注解,表明注解的信息是否添加到java文件中。

注解的定义:

 注解的定义和类,接口,枚举的定义类似,不过它使用@interfaces定义,如:

package com.lt.qlife.annotation;

import com.lt.qlife.R;

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

/**
 * Created by luotong on 2017/9/20.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface UIInject {
    int contentViewId() default -1;
    int toolbarId() default R.id.toolbar;
    String title() default "";
    int titleId() default R.id.title;
}

@interface表明这是一个注解,在它上面用元注解给它定义数据,如Target表明这个注解作用于类,接口..上面,在运行时有效,同时可以被继承。下面的类似方法的方法名表明该注解的属性名,返回值表明属性的类型,用default定义属性的默认值。这里contentViewId的默认值为-1和title的默认值为“”是一种技巧,可以通过设置默认值可以判断该属性是否被赋值。

注解的作用:

 注解是一种元数据,用来给类,接口,域等定义数据,不包含业务逻辑,因此我们需要根据注解定义的数据来自己定义业务逻辑,如我们在BaseActivity中可以根据子类的UIinject类设置contentView及toolbar的属性等:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if(getClass().isAnnotationPresent(UIInject.class)){
        UIInject annotation = getClass().getAnnotation(UIInject.class);
        mContentViewId = annotation.contentViewId();
        setContentView(mContentViewId);
        mToolbar = (Toolbar) findViewById(annotation.toolbarId());
        mTitle = (TextView) findViewById(annotation.titleId());
        if(mTitle != null) {
            mTitle.setText(annotation.title());
        }
        if(mToolbar != null) {
            setSupportActionBar(mToolbar);
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onBackPressed();
                }
            });
        }
    }
    init();
    initView();
    initData();
}

由于UIinject被定义为运行时有效,我们可以通过Class的isAnnotationPresent方法判断注解是否存在,如果存在那么可以通过Class的getAnnotation方法得到这个注解的实例,然后拿到注解属性定义的数据,最后根据注解得到的数据来初始化我们的控件。

注解的使用:

 定义好了注解及我们的业务逻辑,那么我们接下来就是使用注解了,如:

@UIInject(contentViewId = R.layout.activity_main)
public class MainActivity extends BaseActivity{

}

这样一来,我们就不需要在MainActivity中使用setContentView方法设置contentView了,同时如果多个Activity都使用了Toolbar,我们只需要在注解中标识Toolbar的相关属性值就可以了,这样可以使得我们代码变得更加简单清晰。

你可能感兴趣的:(Android进阶,Android进阶)