android注解入门 并来自己写一个框架.doc_第1页
android注解入门 并来自己写一个框架.doc_第2页
android注解入门 并来自己写一个框架.doc_第3页
android注解入门 并来自己写一个框架.doc_第4页
android注解入门 并来自己写一个框架.doc_第5页
已阅读5页,还剩15页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

android注解入门 并来自己写一个框架介绍这里我带大家来学习一下注解 并且用来写下一个模仿xUtils3 中View框架 此框架 可以省略activity或者fragment的 findViewById 或者设置点击事件的烦恼如下代码:fragmentpackage .myapplication;import android.os.Bundle;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import .mylibrary.FmyClickView;import .mylibrary.FmyContentView;import .mylibrary.FmyViewInject;import .mylibrary.FmyViewView;/你的fragment的布局id Your fragments LayoutIdFmyContentView(R.layout.fragment_blank)public class BlankFragment extends Fragment /你想实例化控件的id /Do you want to control instance id / 等价于 findViewByid /Equivalent to the findViewByid FmyViewView(R.id.tv1) TextView tv1; FmyViewView(R.id.tv2) TextView tv2; Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) /初始化fragment Initialize Fragement return FmyViewInject.injectfragment(this,inflater,container); /你想给哪个控件添加 添加事件 的id /Do you want to add add event id to which controls FmyClickView(R.id.tv1,R.id.tv2) public void myOnclick(View view) switch (view.getId() case R.id.tv1: tv1.setText(TV1 +Math.random()*100); break; case R.id.tv2: tv2.setText(TV2 +Math.random()*100); break; default: Activitypackage .myapplication;import android.os.Bundle;import android.support.v4.app.FragmentTransaction;import android.support.v7.app.AppCompatActivity;import android.widget.FrameLayout;import .mylibrary.FmyContentView;import .mylibrary.FmyViewInject;import .mylibrary.FmyViewView;FmyContentView(R.layout.activity_main)public class MainActivity extends AppCompatActivity FmyViewView(R.id.fl) FrameLayout fl; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); /initActivity / 初始化activity FmyViewInject.inject(this); Override protected void onResume() super.onResume(); FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.fl,new BlankFragment(); fragmentTmit(); java注解学习要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。元注解:元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:1.Target,2.Retention,3.Documented,4.Inherited这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。Target:Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)取值(ElementType)有:1.CONSTRUCTOR:用于描述构造器2.FIELD:用于描述域3.LOCAL_VARIABLE:用于描述局部变量4.METHOD:用于描述方法5.PACKAGE:用于描述包6.PARAMETER:用于描述参数7.TYPE:用于描述类、接口(包括注解类型) 或enum声明使用实例:复制代码Target(ElementType.TYPE)public interface Table /* * 数据表名称注解,默认值为类名称 * return */ public String tableName() default className;Target(ElementType.FIELD)public interface NoDBColumn 复制代码注解Table 可以用于注解类、接口(包括注解类型) 或enum声明,而注解NoDBColumn仅可用于注解类的成员变量。Retention:Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)取值(RetentionPoicy)有:1.SOURCE:在源文件中有效(即源文件保留)2.CLASS:在class文件中有效(即class保留)3.RUNTIME:在运行时有效(即运行时保留)Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。具体实例如下:复制代码Target(ElementType.FIELD)Retention(RetentionPolicy.RUNTIME)public interface Column public String name() default fieldName; public String setFuncName() default setField; public String getFuncName() default getField; public boolean defaultDBValue() default false;复制代码 Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理Documented:Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。复制代码Target(ElementType.FIELD)Retention(RetentionPolicy.RUNTIME)Documentedpublic interface Column public String name() default fieldName; public String setFuncName() default setField; public String getFuncName() default getField; public boolean defaultDBValue() default false;复制代码Inherited:Inherited 元注解是一个标记注解,Inherited阐述了某个被标注的类型是被继承的。如果一个使用了Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。注意:Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。当Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。实例代码:复制代码/* * * author peida * */Inheritedpublic interface Greeting public enum FontColor BULE,RED,GREEN; String name(); FontColor fontColor() default FontColor.GREEN;复制代码自定义注解:使用interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。定义注解格式:public interface 注解名 定义体注解参数的可支持数据类型:1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)2.String类型3.Class类型4.enum类型5.Annotation类型6.以上所有类型的数组Annotation类型里面的参数该怎么设定: 第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型; 第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;第三,如果只有一个参数成员,最好把参数名称设为value,后加小括号.例:下面的例子FruitName注解就只有一个参数成员。简单的自定义注解和使用注解实例:复制代码package annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/* * 水果名称注解 * author peida * */Target(ElementType.FIELD)Retention(RetentionPolicy.RUNTIME)Documentedpublic interface FruitName String value() default ;复制代码复制代码package annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/* * 水果颜色注解 * author peida * */Target(ElementType.FIELD)Retention(RetentionPolicy.RUNTIME)Documentedpublic interface FruitColor /* * 颜色枚举 * author peida * */ public enum Color BULE,RED,GREEN; /* * 颜色属性 * return */ Color fruitColor() default Color.GREEN;复制代码复制代码package annotation;import annotation.FruitColor.Color;public class Apple FruitName(Apple) private String appleName; FruitColor(fruitColor=Color.RED) private String appleColor; public void setAppleColor(String appleColor) this.appleColor = appleColor; public String getAppleColor() return appleColor; public void setAppleName(String appleName) this.appleName = appleName; public String getAppleName() return appleName; public void displayName() System.out.println(水果的名字是:苹果); 复制代码注解元素的默认值:注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。例如:复制代码 1 package annotation; 2 3 import java.lang.annotation.Documented; 4 import java.lang.annotation.ElementType; 5 import java.lang.annotation.Retention; 6 import java.lang.annotation.RetentionPolicy; 7 import java.lang.annotation.Target; 8 9 /*10 * 水果供应者注解11 * author peida12 *13 */14 Target(ElementType.FIELD)15 Retention(RetentionPolicy.RUNTIME)16 Documented17 public interface FruitProvider 18 /*19 * 供应商编号20 * return21 */22 public int id() default -1;23 24 /*25 * 供应商名称26 * return27 */28 public String name() default ;29 30 /*31 * 供应商地址32 * return33 */34 public String address() default ;35 复制代码activity设置填充布局框架这里我们先写一个用于activity框架 你学习完了之后其实你也会fragment了. 1. 实现activity不需要调用setContentView(R.layout.activity_main);此方法完成布局填充 我们看下效果 不使用框架:package .mylibrary;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;public class MainActivity extends AppCompatActivity Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); 使用框架:package .mylibrary;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;FmyContentView(R.layout.activity_main)public class MainActivity extends AppCompatActivity Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); FmyViewInject.inject(this); 第一步: 创建一个注解类如下 Target 此注解在什么地方可以使用 如类还是变量 ElementType.TYPE只能在类中使用此注解 Retention(RetentionPolicy.RUNTIME) 注解可以在运行时通过反射获取一些信息(这里如果你疑惑那么请六个悬念继续向下看)/* * 此方注解写于activity类上 可以免去 setContentView()步骤 * author 范明毅 * version 1.0 */Target(ElementType.TYPE)Retention(RetentionPolicy.RUNTIME)Documentedpublic interface FmyContentView /* * 保存布局文件的id eg:R.layout.main * return 返回 布局id */ int value();第二步: 写一个工具类 配合注解使用 当开发者使用此类时激活注解的作用public class FmyViewInject /* * 保存传入的activity */ private static Class activityClass; /* * 初始化activity和所有注解 * * param obj * 你需要初始化的activity */ public static void inject(Object obj) /* * 初始化activity布局文件 让其不用调用setContentView * * param activity */ private static void injectContent(Object obj) 大家先不用着急看不懂为什么这样写原因核心源码位于injectContent 我们来实现此方法 /* * 初始化activity布局文件 让其不用调用setContentView * * param activity */ private static void injectContent(Object obj) / 获取注解 FmyContentView annotation = activityClass .getAnnotation(FmyContentView.class); if (annotation != null) / 获取注解中的对应的布局id 因为注解只有个方法 所以XXX(YYY)时会自动赋值给注解类唯一的方法 int id = annotation.value(); try / 得到activity中的方法 第一个参数为方法名 第二个为可变参数 类型为 参数类型的字节码 Method method = activityClass.getMethod(setContentView, int.class); / 调用方法 第一个参数为哪个实例去掉用 第二个参数为 参数 method. invoke(obj, id); catch (Exception e) e.printStackTrace(); 此方法写完后工具类的inject()方法调用即可 /* * 初始化activity和所有注解 * * param obj * 你需要初始化的activity */ public static void inject(Object obj) activityClass = obj.getClass(); / 初始化activity布局文件 injectContent(obj); 完整代码:public class FmyViewInject /* * 保存传入的activity */ private static Class activityClass; /* * 初始化activity和所有注解 * * param obj * 你需要初始化的activity */ public static void inject(Object obj) activityClass = obj.getClass(); / 初始化activity布局文件 injectContent(obj); /* * 初始化activity布局文件 让其不用调用setContentView * * param activity */ private static void injectContent(Object obj) / 获取注解 FmyContentView annotation = activityClass .getAnnotation(FmyContentView.class); if (annotation != null) / 获取注解中的对应的布局id 因为注解只有个方法 所以XXX(YYY)时会自动赋值给注解类唯一的方法 int id = annotation.value(); try / 得到activity中的方法 第一个参数为方法名 第二个为可变参数 类型为 参数类型的字节码 Method method = activityClass.getMethod(setContentView, int.class); / 调用方法 第一个参数为哪个实例去掉用 第二个参数为 参数 method.invoke(obj, id); catch (Exception e) e.printStackTrace(); 赶快去试试 我们继续写下一步 用法在开始的示例有activity查找控件效果如下FmyContentView(R.layout.activity_main)public class MainActivity extends FragmentActivity /直接实例化 FmyViewView(R.id.fl) private FrameLayout fl; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); FmyViewInject.inject(this); 第一步: 继续写一个注解/* * 此方注解写于activity类中 控件变量上 可以省去findViewId 的烦恼 * author 范明毅 * version 1.0 */Target(ElementType.FIELD)Retention(RetentionPolicy.RUNTIME)public interface FmyViewView /* * 保存view控件的id * return view控件id */ int value();第二步 继续第一节的”activity设置填充布局框架”中的工具类添加新的方法 /* * 初始化activity中的所有view控件 让其不用一个findViewid 实例化 * * param activity */ private static void injectView(Object activityOrFragment) / 对象所有的属性 Field declaredFields = null; / 健壮性 if (activityClass != null) / 获取du所有的属性 包含私有 保护 默认 共开 但不包含继承等 / getFields可以获取到所有公开的包括继承的 但无法获取到私有的属性 declaredFields = activityClass.getDeclaredFields(); / 健壮性 if (declaredFields != null) / 遍历所有的属性变量 for (Field field : declaredFields) / 获取属性变量上的注解 FmyViewView annotation = field.getAnnotation(FmyViewView.class); / 如果此属性变量 包含FMYViewView if (annotation != null) / 获取属性id值 int id = annotation.value(); Object obj = null; try / 获取activity中方法 obj = activityClass.getMethod(findViewById, int.class).invoke(activityOrFragment, id); Log.e(FMY, + field.getClass(); / 设置属性变量 指向实例 / 如果修饰符不为公共类 这里注意了 当activity / 控件变量为private的时候 我们去访问会失败的 要么打破封装系 要么变量改为public /如 private TextView tv 这种情况 如果不打破封装会直接异常 if (Modifier.PUBLIC != field.getModifiers() / 打破封装性 field.setAccessible(true); / 这里相当于 field= acitivity.obj field.set(activityOrFragment, obj); catch (Exception e) / TODO Auto-generated catch block e.printStackTrace(); 第三步 在工具类中的inject ()方法调用 /* * 初始化activity和所有注解 * * param obj 你需要初始化的activity */ public static void inject(Object obj) activityClass = obj.getClass(); / 初始化activity布局文件 injectContent(obj); / 初始化所有控件实例 省去findViewId的痛苦 injectView(obj); activity设置控件的点击事件这里需要的知识点 如动态代理等 这里大家可以自己百度看下 效果如下FmyContentView(R.layout.activity_main)public class MainActivity extends FragmentActivity FmyViewView(R.id.fl) private FrameLayout fl; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); FmyViewInject.inject(this); /当填充的布局中 id为R.id.fl 被点击将调用如下方法 FmyClickView(R.id.fl) public void onClick(View v) Log.e(fmy, =); 第一步 : 同样写下一个注解/* * * 设置点击事件的注解 只需要在某方法 上写上此注解即可 如FmyClickView(R.id.bt1,R.id.bt2) * version 1.0 * author 范明毅 * */Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)public interface FmyClickView /* * 保存所有需要设置点击事件控件的id * return */ int value();第二步: 写下一个代理处理类(我写在工具类中)/* * 代理处理点击逻辑代码 * * author 范明毅 * */ static class MInvocationHandler implements InvocationHand

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论