




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】怎么在Android中使用反射注解与动态代理
今天就跟大家聊聊有关怎么在Android中使用反射注解与动态代理,可能很多人都不太了解,为了让大家更加了解,在下给大家总结了以下内容,希望大家根据这篇文章可以有所收获。反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高比较常用的方法getDeclaredFields():可以获得class的成员变量getDeclaredMethods():可以获得class的成员方法getDeclaredConstructors():可以获得class的构造函数注解Java代码从编写到运行会经过三个大的时期:代码编写,编译,读取到JVM运行,针对三个时期分别有三类注解:public
enum
RetentionPolicy
{
/**
*
Annotations
are
to
be
discarded
by
the
compiler.
*/
SOURCE,
/**
*
Annotations
are
to
be
recorded
in
the
class
file
by
the
compiler
*
but
need
not
be
retained
by
the
VM
at
run
time.
This
is
the
default
*
behavior.
*/
CLASS,
/**
*
Annotations
are
to
be
recorded
in
the
class
file
by
the
compiler
and
*
retained
by
the
VM
at
run
time,
so
they
may
be
read
reflectively.
*
*
@see
java.lang.reflect.AnnotatedElement
*/
RUNTIME
}SOURCE:就是针对代码编写阶段,比如@Override注解CLASS:就是针对编译阶段,这个阶段可以让编译器帮助我们去动态生成代码RUNTIME:就是针对读取到JVM运行阶段,这个可以结合反射使用,我们今天使用的注解也都是在这个阶段使用注解还需要指出注解使用的对象public
enum
ElementType
{
/**
Class,
interface
(including
annotation
type),
or
enum
declaration
*/
TYPE,
/**
Field
declaration
(includes
enum
constants)
*/
FIELD,
/**
Method
declaration
*/
METHOD,
/**
Formal
parameter
declaration
*/
PARAMETER,
/**
Constructor
declaration
*/
CONSTRUCTOR,
/**
Local
variable
declaration
*/
LOCAL_VARIABLE,
/**
Annotation
type
declaration
*/
ANNOTATION_TYPE,
/**
Package
declaration
*/
PACKAGE,
/**
*
Type
parameter
declaration
*
*
@since
1.8
*
@hide
1.8
*/
TYPE_PARAMETER,
/**
*
Use
of
a
type
*
*
@since
1.8
*
@hide
1.8
*/
TYPE_USE
}比较常用的方法TYPE作用对象类/接口/枚举FIELD成员变量METHOD成员方法PARAMETER方法参数ANNOTATION_TYPE注解的注解下面看下自己定义的三个注解@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public
@interface
InjectView
{
int
value();
}InjectView用于注入view,其实就是用来代替findViewById方法Target指定了InjectView注解作用对象是成员变量Retention指定了注解有效期直到运行时时期value就是用来指定id,也就是findViewById的参数@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@EventType(listenerType
=
View.OnClickListener.class,
listenerSetter
=
"setOnClickListener",
methodName
=
"onClick")
public
@interface
onClick
{
int[]
value();
}onClick注解用于注入点击事件,其实用来代替setOnClickListener方法Target指定了onClick注解作用对象是成员方法Retention指定了onClick注解有效期直到运行时时期value就是用来指定id,也就是findViewById的参数@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public
@interface
EventType
{
Class
listenerType();
String
listenerSetter();
String
methodName();
}在onClikc里面有一个EventType定义Target指定了EventType注解作用对象是注解,也就是注解的注解Retention指定了EventType注解有效期直到运行时时期listenerType用来指定点击监听类型,比如OnClickListenerlistenerSetter用来指定设置点击事件方法,比如setOnClickListenermethodName用来指定点击事件发生后会回调的方法,比如onClick综合使用接下来我用一个例子来演示如何使用反射、注解、和代理的综合使用@InjectView(R.id.bind_view_btn)
Button
mBindView;在onCreate中调用注入Utils.injectView(this);我们看下Utils.injectView这个方法的内部实现public
static
void
injectView(Activity
activity)
{
if
(null
==
activity)
return;
Class<?
extends
Activity>
activityClass
=
activity.getClass();
Field[]
declaredFields
=
activityClass.getDeclaredFields();
for
(Field
field
:
declaredFields)
{
if
(field.isAnnotationPresent(InjectView.class))
{
//解析InjectView
获取button
id
InjectView
annotation
=
field.getAnnotation(InjectView.class);
int
value
=
annotation.value();
try
{
//找到findViewById方法
Method
findViewByIdMethod
=
activityClass.getMethod("findViewById",
int.class);
findViewByIdMethod.setAccessible(true);
findViewByIdMethod.invoke(activity,
value);
}
catch
(NoSuchMethodException
e)
{
e.printStackTrace();
}
catch
(InvocationTargetException
e)
{
e.printStackTrace();
}
catch
(IllegalAccessException
e)
{
e.printStackTrace();
}
}
}
}1.方法内部首先拿到activity的所有成员变量,2.找到有InjectView注解的成员变量,然后可以拿到button的id3.通过反射activityClass.getMethod可以拿到findViewById方法4.调用findViewById,参数就是id。可以看出来最终都是通过findViewById进行控件的实例化接下来看一下如何将onClick方法的调用映射到activity中的invokeClick()方法首先在onCreate中调用注入Utils.injectEvent(this);@onClick({R.id.btn_bind_click,
R.id.btn_bind_view})
public
void
invokeClick(View
view)
{
switch
(view.getId())
{
case
R.id.btn_bind_click:
Log.i(Utils.TAG,
"bind_click_btn
Click");
Toast.makeText(MainActivity.this,"button
onClick",Toast.LENGTH_SHORT).show();
break;
case
R.id.btn_bind_view:
Log.i(Utils.TAG,
"bind_view_btn
Click");
Toast.makeText(MainActivity.this,"button
binded",Toast.LENGTH_SHORT).show();
break;
}
}反射+注解+动态代理就在injectEvent方法中,我们现在去揭开女王的神秘面纱public
static
void
injectEvent(Activity
activity)
{
if
(null
==
activity)
{
return;
}
Class<?
extends
Activity>
activityClass
=
activity.getClass();
Method[]
declaredMethods
=
activityClass.getDeclaredMethods();
for
(Method
method
:
declaredMethods)
{
if
(method.isAnnotationPresent(onClick.class))
{
Log.i(Utils.TAG,
method.getName());
onClick
annotation
=
method.getAnnotation(onClick.class);
//get
button
id
int[]
value
=
annotation.value();
//get
EventType
EventType
eventType
=
annotation.annotationType().getAnnotation(EventType.class);
Class
listenerType
=
eventType.listenerType();
String
listenerSetter
=
eventType.listenerSetter();
String
methodName
=
eventType.methodName();
//创建InvocationHandler和动态代理(代理要实现listenerType,这个例子就是处理onClick点击事件)
ProxyHandler
proxyHandler
=
new
ProxyHandler(activity);
Object
listener
=
Proxy.newProxyInstance(listenerType.getClassLoader(),
new
Class[]{listenerType},
proxyHandler);
proxyHandler.mapMethod(methodName,
method);
try
{
for
(int
id
:
value)
{
//找到Button
Method
findViewByIdMethod
=
activityClass.getMethod("findViewById",
int.class);
findViewByIdMethod.setAccessible(true);
View
btn
=
(View)
findViewByIdMethod.invoke(activity,
id);
//根据listenerSetter方法名和listenerType方法参数找到method
Method
listenerSetMethod
=
btn.getClass().getMethod(listenerSetter,
listenerType);
listenerSetMethod.setAccessible(true);
listenerSetMethod.invoke(btn,
listener);
}
}
catch
(NoSuchMethodException
e)
{
e.printStackTrace();
}
catch
(InvocationTargetException
e)
{
e.printStackTrace();
}
catch
(IllegalAccessException
e)
{
e.printStackTrace();
}
}
}
}1.首先就是获取activity的所有成员方法getDeclaredMethods2.找到有onClick注解的方法,拿到value就是注解点击事件button的id3.获取onClick注解的注解EventType的参数,从中可以拿到设定点击事件方法setOnClickListener+点击事件的监听接口OnClickListener+点击事件的回调方法onClick4.在点击事件发生的时候Android系统会触发onClick事件,我们需要将事件的处理回调到注解的方法invokeClick,也就是代理的思想5.通过动态代理Proxy.newProxyInstance实例化一个实现OnClickListener接口的代理,代理会在onClick事件发生的时候回调InvocationHandler进行处理6.RealSubject就是activity,因此我们传入ProxyHandler实例化一个InvocationHandler,用来将onClick事件映射到activity中我们注解的方法InvokeBtnClick7.通过反射实例化Button,findViewByIdMethod.invoke8.通过Button.setOnClickListener(OnClickList
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 中介房产托管合同范例
- 写销售合同范例
- 临淄区劳务派遣合同范例
- 共同房子合同范例
- 不动产权房屋买卖合同范例
- 养殖基地供货合同范例
- 党建活动推广合同范例
- 供货合同范例肉
- 养猪场签约合同范例
- 军服布料采购合同范例
- GB/T 4857.4-2008包装运输包装件基本试验第4部分:采用压力试验机进行的抗压和堆码试验方法
- GB/T 29617-2013数字密度计测试液体密度、相对密度和API比重的试验方法
- 故宫博物院笔试试题
- 思政教育融入小学语文教学的策略研究
- 供方准入申请表
- DDI领导力-高绩效辅导课件
- 《烟酒有危害》公开课教案
- 高三生物一轮复习课件:生物变异类型的判断与实验探究
- 先简支后连续T梁桥设计计算书
- 机械制造及其自动化专业毕业设计(1)解读
- (完整word版)桩位偏差验收记录表
评论
0/150
提交评论