Android开发 打造自己的Annotation框架
来源:互联网 发布:广州恒大淘宝股票 编辑:程序博客网 时间:2024/05/20 06:24
最近在回顾注解和反射方面的知识。
之前在项目开发过程中,也曾经体验过ButterKnife的注解,想结合反射和注解自己写一个框架。结合着大牛的博客,和自己的理解。实现了Activity加载layout和view初始化的注解。
一.原理
package csu.lzw.reviewandroid.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by Allen_Binan on 2016/4/2. */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface LBindView { int id() default -1;}
@Target用来表示这个注解修饰的对象是什么,FIELD表示是成员变量,例如Actvity当中的View控件。
@Retentiong表示这个注解是在什么级别保存信息。RUNTIME表示是运行时。
@interface是用于自定义注解的,它里面定义的方法的声明不能有参数,也不能抛出异常,并且方法的返回值被限制为简单类型、String、Class、emnus、@interface,和这些类型的数组。
注解@Target也是用来修饰注解的元注解,它有一个属性ElementType也是枚举类型,值为:ANNOTATION_TYPE,CONSTRUCTOR ,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER和TYPE,如@Target(ElementType.METHOD) 修饰的注解表示该注解只能用来修饰在方法上。
@RetentionRetention注解表示需要在什么级别保存该注释信息,用于描述注解的生命周期,它有一个RetentionPolicy类型的value,是一个枚举类型,它有以下的几个值:
1.用@Retention(RetentionPolicy.SOURCE)修饰的注解,指定注解只保留在源文件当中,编译成类文件后就把注解去掉;
2.用@Retention(RetentionPolicy.CLASS)修饰的注解,指定注解只保留在源文件和编译后的class 文件中,当jvm加载类时就把注解去掉;
3.用@Retention(RetentionPolicy.RUNTIME )修饰的注解,指定注解可以保留在jvm中,这样就可以使用反射获取信息了。
默认是RUNTIME,这样我们才能在运行的时候通过反射获取并做对应的逻辑处理。
同理可得,用于修饰Activity类,而加载layout布局的注解。
package csu.lzw.reviewandroid.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Created by Allen_Binan on 2016/4/2. */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface LBindContentView { int layoutId() default -1;}
最终,在Activity中实现的效果如下
package csu.lzw.reviewandroid;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.Button;import csu.lzw.reviewandroid.annotation.LBindContentView;import csu.lzw.reviewandroid.annotation.LBindView;import csu.lzw.reviewandroid.annotation.LViewBindUtils;@LBindContentView(layoutId = R.layout.activity_main)public class MainActivity extends AppCompatActivity { private static final String TAG="MainActivity"; @LBindView(id=R.id.toggleButton) private Button tg; @LBindView(id = R.id.toggleButton2) private Button tg2; @LBindView(id = R.id.toggleButton3) private Button tg3; @LBindView(id = R.id.toggleButton4) private Button tg4; @LBindView(id = R.id.toggleButton5) private Button tg5; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LViewBindUtils.inject(this); tg.setText("test"); tg2.setText("test2"); }}
关键的实现在于这一步
LViewBindUtils.inject(this);
这一步里做了什么呢
对于初始化view的注解,那么获取this指向的Activity中的成员,检查成员中是否有自定义的注解,如果有的话,获取注解中声明的id,使用反射,获取Activity的findviewbyid方法,使用invode调用,并将返回值通过反射赋值给将要初始化的view.
对于加载Activity布局的view,类似地,检查activity类上有没有自定义的注解,如果有的话,通过反射,调用setcontentview.
package csu.lzw.reviewandroid.annotation;import java.lang.reflect.Field;import java.lang.reflect.Method;import android.app.Activity;import android.util.Log;public class LViewBindUtils{private static final String METHOD_SET_CONTENTVIEW = "setContentView";private static final String METHOD_FIND_VIEW_BY_ID = "findViewById";public static void inject(Activity activity){injectContentView(activity);injectViews(activity);// injectEvents(activity);}/** * 注入所有的view控件 * * @param activity */private static void injectViews(Activity activity){Class<? extends Activity> clazz = activity.getClass();Field[] fields = clazz.getDeclaredFields();// 遍历所有成员变量for (Field field : fields){LBindView viewInjectAnnotation = field.getAnnotation(LBindView.class);if (viewInjectAnnotation != null){int viewId = viewInjectAnnotation.id();if (viewId != -1){// 初始化Viewtry{Method method = clazz.getMethod(METHOD_FIND_VIEW_BY_ID,int.class);Object resView = method.invoke(activity, viewId);field.setAccessible(true);field.set(activity, resView);} catch (Exception e){e.printStackTrace();}}}}}/** * 注入主布局文件 * * @param activity */private static void injectContentView(Activity activity){Class<? extends Activity> clazz = activity.getClass();// 查询类上是否存在ContentView注解LBindContentView contentView = clazz.getAnnotation(LBindContentView.class);if (contentView != null)// 存在{int contentViewLayoutId = contentView.layoutId();try{Method method = clazz.getMethod(METHOD_SET_CONTENTVIEW,int.class);method.setAccessible(true);method.invoke(activity, contentViewLayoutId);} catch (Exception e){e.printStackTrace();}}}}
- Android开发 打造自己的Annotation框架
- Android打造自己的网络框架----Rxlifecycle的使用
- 打造自己的注解框架
- 打造自己的php框架
- 打造自己的MVC框架
- Android中使用注解打造自己的IOC框架
- Android视频框架 Vitamio 打造自己的万能播放器
- Android视频框架 Vitamio 打造自己的万能播放器
- Android视频框架 Vitamio 打造自己的万能播放器
- Android视频框架 Vitamio 打造自己的万能播放器
- Android视频框架 Vitamio 打造自己的万能播放器
- Android 自己打造IOC注解框架
- <Android> 打造自己的进度条
- Android注入框架你应该知道的一切------打造自己的注入框架
- Android注入框架你应该知道的一切------打造自己的注入框架
- 轻松打造自己的AJAX框架
- 打造自己的RMS框架(三)
- php打造属于自己的MVC框架-
- [core java学习笔记][第四章对象与类]
- 计算机网络overview-1
- tomcat配置自定义JDK
- [core java学习笔记][第五章继承]
- Problem D: C语言习题 a!+b!+c!
- Android开发 打造自己的Annotation框架
- [core java学习笔记][第六章接口与内部类]
- Codeforces 656 B. Scrambled(April Fools Day Contest 2016)
- Android开发解决The connection to adb is down, and a severe error has occured. 问题
- import com.sun.image.codec.jpeg.JPEGCodec不通过 找不到包
- [core java学习笔记][第十章部署应用程序]
- HDU - 5288-OO’s Sequence-数学+分类再二分+枚举+contribution costing
- 机器学习:贝叶斯网络入门
- SDAU课程练习2 1017