【移动应用开发技术】怎么在Android中使用反射注解与动态代理_第1页
【移动应用开发技术】怎么在Android中使用反射注解与动态代理_第2页
【移动应用开发技术】怎么在Android中使用反射注解与动态代理_第3页
【移动应用开发技术】怎么在Android中使用反射注解与动态代理_第4页
【移动应用开发技术】怎么在Android中使用反射注解与动态代理_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

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

文档简介

【移动应用开发技术】怎么在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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论