Android annotation

Annotations are special code markers that can be compiled, class loading, the runtime is read, and performs a corresponding process.

Read at runtime uses the Java reflection mechanism for processing.

First, the role of notes:

Notes have been some repetitive work into the program automatically, simplify and automate the process. Such as for generating Java doc, such as format compile time checking, such as automatic generation of code, etc., to enhance the quality and productivity software software.

Second, what are notes

1, Java provides four yuan notes, specifically responsible for creating new annotation work, that other annotation notes.

@Target
defines the Annotation of the modified target range of values: 

ElementType.CONSTRUCTOR: constructor is used to describe

ElementType.FIELD: a description field

ElementType.LOCAL_VARIABLE: local variables used to describe the

ElementType.METHOD: a description of the method

ElementType.PACKAGE: used to describe the package

ElementType.PARAMETER: parameter used to describe the

ElementType.TYPE: used to describe the class, interface (including type of annotation), or an enum declaration

@Retention
defines the length of time that Annotation is reserved values:

 - RetentionPoicy.SOURCE: Notes only retained in the source file, when compiled Java class file into a file, annotations are abandoned; do something for the examination of such @Override and @SuppressWarnings
 - RetentionPoicy.CLASS: annotations are reserved to class file, the class file is loaded when jvm abandoned, which is a default lifetime; for some compile-time preprocessing operations, such as creating some of the ancillary code (e.g. ButterKnife)
 - RetentionPoicy.RUNTIME: annotation is saved not only to class file, after jvm loaded class files still exist; get used to the dynamic annotation information at run time.
 

@Documented
mark notes, used to describe other types of notes should be as a member of the public API program is marked, it can be such a tool such as javadoc documentation, no assignment.

@Inherited
mark notes, annotations allow subclass inherits the parent class. Here a little bit not begin to understand the need to punctuate it allows annotation subclass inherits the parent class.

2, Android SDK built-in notes

Android SDK built-in annotation package com.android.support:support-annotations, the following in order to 'com.android.support:support-annotations:25.2.0' A Case Study

Restricted resource references: for limiting parameters corresponding to the resource type must
@AnimRes @AnyRes @ArrayRes @AttrRes @BoolRes @ColorRes etc.

Thread execution restriction class: Method for limiting or class must be executed in the specified thread
@AnyThread @BinderThread @MainThread @UiThread @WorkerThread

Class restriction parameter is empty: if for limiting the parameter can be null
@Nullable @NonNull

Type restricted range: range of values for limiting label value
@FloatRang @IntRange

Class type definitions: annotation definition for limiting value set
@IntDef @StringDef

Other functional annotation:
@CallSuper @CheckResult @ColorInt @Dimension @Keep @Px @RequiresApi @RequiresPermission @RestrictTo @Size @VisibleForTesting

3, custom annotations. . . .

Third, how to use Android Annotation

build.gradle

dependencies {
  androidTestCompile('com.android.support:support-annotations:26.1.0') {
    force = true
  }
}

for example:

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

  

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

  

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

  

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

  

public class AnnotationParse {


    private static AnnotationParse instance;

    public static AnnotationParse getInstance() {
        if (instance == null) {
            synchronized (AnnotationParse.class) {
                if (instance == null) {
                    instance = new AnnotationParse();
                    return instance;
                }
            }
        }
        return instance;
    }

    public void bind(Activity activity) throws IllegalAccessException {
        try {
            injectLayout(activity);
            bindView(activity);
            bindOnClick(activity);
            injectEvent (Activity); 
                //. 4, get the value of the notes
        The catch} (Exception EX) { 

        } 
    } 

    Private static void bindView (Activity Activity) throws IllegalAccessException { 
        //. 1, obtaining bytecodes 
        Class aClass = activity.getClass () <the extends Activity?>; 

        // 2, obtaining the variable Activity 
        Field, [] = declaredField aClass.getDeclaredFields (); 

        for (Field, Field: declaredField) { 
            // set allows violence reflected 
            field.setAccessible (to true); 
            //. 3, the acquired comment variable 
            ViewById annotation = field.getAnnotation (ViewById. class); 
            IF (Annotation = null) {! 
                int ID = annotation.value (); 
                //. 5, control by acquiring ID 
                View View = activity.findViewById (ID); 
                //. 6, the control assigned to the variable 
                field.set (Activity, View); 
            } 
        } 
    } 

    // OnClick annotation of "interpretation" 
    Private static bindOnClick void (the Activity Activity Final) { 
        //. 1, obtaining bytecode object 
        Final Class aClass = activity.getClass () <the extends the Activity?>; 
        // 2, an overview of all methods 
        method [] declaredMethods = aClass.getDeclaredMethods () ; 
        // 3, through all methods 
        for (Final method, method: declaredMethods) { 
            method.setAccessible (to true); 
            //. 4, the method of obtaining annotation 
            the OnClick Annotation = method.getAnnotation (OnClick.class); 
            IF (Annotation = null!) {
                int id = annotation.value();
                View view = activity.findViewById(id);
                view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        try {
                            //执行注解的方法
                            method.invoke(activity, null);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    }


    private static void injectEvent(final Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        for (final Method method2 : methods) {
            BtnOnClick click = method2.getAnnotation(BtnOnClick.class);
            if (click != null) {
                int[] viewId = click.value();
                method2.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 method2.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();
                }
            }
        }
    }


    private static int mLayoutId = -1;

    /**
     * 注解布局Layout id
     */
    private static void injectLayout(Activity activity) {
        Class<?> clazz = activity.getClass();
        if (clazz.getAnnotations() != null) {
            if (clazz.isAnnotationPresent(LayoutInject.class)) {
                LayoutInject inject = clazz.getAnnotation(LayoutInject.class);
                mLayoutId = inject.value();
                activity.setContentView(mLayoutId);
            }
        }

    }

}

  

@LayoutInject(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {

    @ViewById(R.id.tvName)
    TextView tvName;

    @ViewById(R.id.tvAge)
    TextView tvAge;

    @ViewById(R.id.tvGender)
    TextView tvGender;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);
        try {
            AnnotationParse.getInstance().bind(this);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        tvName.setText("测试名字");
        tvAge.setText("28");
        tvGender.setText("男");
    }

    @BtnOnClick({R.id.tvName, R.id.tvAge, R.id.tvGender})
    public void btnOnClick(View view) {
        switch (view.getId()) {
            case R.id.tvName:
                tvName.setText("华山论剑");
                break;
            case R.id.tvAge:
                tvAge.setText("四百多岁");
                break;
            case R.id.tvGender:
                tvGender.setText("女");
                break;
        }
    }


    @OnClick(R.id.tvName)
    public void textOnClick() {
        tvName.setText("First sword "); 
    }
}

  

Guess you like

Origin www.cnblogs.com/candyzhmm/p/12169808.html