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 "); } }