注解框架的原理理解

关注注解 我想都不陌生了,Android上采用注解来快速开发 我在实际工作中还没试过,这里简介记录一下我对Android注解框架的理解。

注解在Android开发中大致可以分为用在 方法 、成员、和 事件上,其他暂时不考虑。

本文参考知名博主张鸿洋的 关于IOC的描述  地址:

http://blog.csdn.net/lmj623565791/article/details/39269193

一、注解反射成员变量和 方法。编写反射@interface  xxx

引用注解,反射得到注解的值,
传递进入当前Context反射得到Method。Field 等,然后执行invoke 方法即可
这样可以通过注解反射成员变量(可以初始化控件),成员方法(加载布局文件)等。比较简单。

btn = findViewById:可能需要多个btn,因此写注解是多个的。@inject(value=id)

	Class<? extends Activity> clazz = activity.getClass();  
        Field[] fields = clazz.getDeclaredFields();  
        // 遍历所有成员变量  
        for (Field field : fields)  
        {       
            ViewInject viewInjectAnnotation = field.getAnnotation(ViewInject.class); 
	}
setOnContentView(id) :由于一个类只有个layout布局设置,所以只需要一个annotation就行了.(@contentview(value=id))
        Class<? extends Activity> clazz = activity.getClass();  
        ContentView contentView = clazz.getAnnotation(ContentView.class);  

以上是注解反射字段和 反射方法。


二、通过注解注入事件。

下面这样的代码
	btn.setOnclickListener(new View.OnclickListener(){onclick })
将改为:
	@Onclick(value=R.id.btn1,value=R.id.btn2...)
	public void myClick(View v){	}

1、反射得到btn
利用注解拿到id后 findviewById(id),得到Button
2、利用Proxy InvocationHandler 创建接口(View.OnclickListener)的对象,可以自定义一个类实现InvocationHandler 。
例如下面代码:

main:test:

	InvocationHandler i = new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				System.out.println("方法名:"+method.getName());
				System.out.println((args==null)?"没有参数":"参数:"+args[0]);
				System.out.println(method.getReturnType().getName());
				System.out.println();
				return "test result";
			}
		};
		//利用Proxy创建出接口InterfaceTest的对象,
		Object o = Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{InterfaceTest.class}, i);
		//转化为InterfaceTest对象
		InterfaceTest interfaceTest = (InterfaceTest) o;
		//当调用对象的方法时,也就是接口中的方法时就会调用InvocationHandler的invoke方法。上面的i就是代理对象。
		String result1 = interfaceTest.printInfo1();
		interfaceTest.printInfo2();
		String result = interfaceTest.printInfo3("1");
		System.out.println(result);

public	interface InterfaceTest{
	
	public  String printInfo1();
	public  void printInfo2();
	public  String printInfo3(String p);
}

3、反射执行setOnclickListener

总体思想是把下面这句代码,封装起来,只把控件id和自己定义的事件处理方法 提供给程序员来写。

btn.setOnclickListener(new View.OnclickListener(){onclick })
@Onclick(value=R.id.btn1,value=R.id.btn2...)
public void myClick(View v){	}

那么可以推测到有个注解 @interface Onclick。这个@interface Onclick注解里面得完成btn.setOnclickListener(new View.OnclickListener(){onclick }) 操作。而@interface Onclick是个注解。
所以只有在这个注解上再次使用一个注解。于是乎有:

@Target(ElementType.METHOD)  
@Retention(RetentionPolicy.RUNTIME)  
@EventBase(listenerType = View.OnClickListener.class, listenerSetter = "setOnClickListener", methodName = "onClick")  
public @interface Onclick{
	//放置控件的id
	int[] value;
}

那么在 @interface EventBase中来提供 设置listener的元素:监听类的类型(OnclickListener.class),类型名称(setOnclickListener),监听类的方法也就是事件的处理方法
(onClick),有了这三个元素就可以 在验证@interface EventBase注解时 完成btn.setOnClickListener(obj)操作.


下面是实现的代码:

/**
	 * 注入所有的onclick事件
	 * 
	 * @param activity
	 */
	private static void injectEvents(Activity activity)
	{
		
		Class<? extends Activity> clazz = activity.getClass();
		Method[] methods = clazz.getMethods();
		//遍历当前activity中的所有方法
		for (Method method : methods)
		{
			Annotation[] annotations = method.getAnnotations();

			//拿到方法上的所有的注解,这里可以拿到 @interface Onclick注解
			for (Annotation annotation : annotations)
			{
			  Class<? extends Annotation> annotationType = annotation.annotationType();

			//拿到@interface EventBase注解,因为这个注解上提供了反射执行btn.setOnclickListener(obj)的元素。
			//这个注解是@interface Onclick注解上的注解。
				EventBase eventBaseAnnotation = annotationType
						.getAnnotation(EventBase.class);
				//如果设置的为EventBase注解
				if (eventBaseAnnotation != null)
				{
					//取出设置监听器的类型,监听器的名称,监听器的方法(事件回调执行方法onClick)
					String listenerSetter = eventBaseAnnotation.listenerSetter(); //setOnclickListener
					Class<?> listenerType = eventBaseAnnotation.listenerType();//OnclickListener.class
					String methodName = eventBaseAnnotation.methodName();//onClick

					try
					{
						//拿到Onclick注解中的value方法:拿到控件的id,以此可以得到btn控件实例
						Method aMethod = annotationType.getDeclaredMethod("value");

						//取出所有的viewId,value()方法不需要参数,所以是null
						int[] viewIds = (int[]) aMethod.invoke(annotation, null);

						//通过Proxy InvocationHandler创建代理对象。即OnclickListener接口的对象。
					DynamicHandler handler = new DynamicHandler(activity);
					handler.addMethod(methodName, method);// 这句可以不要
					Object listener = Proxy.newProxyInstance(listenerType.getClassLoader(),new Class<?>[] { listenerType }, handler);

					//到此即可设置事件了:

						
						for (int viewId : viewIds)
						{
							//遍历所有的View,创建出view ,
							View view = activity.findViewById(viewId);
							//再利用view反射出事件方法名并得到此方法的Method对象,
							Method setEventListenerMethod = view.getClass().getMethod(listenerSetter, listenerType);

							//最后利用Method对象设置事件即可.btn.setOnclickListener(obj);
							//setOnclickListener方法对象反射执行,参数为所属对象和方法参数。
							setEventListenerMethod.invoke(view, listener);
						}

					} catch (Exception e)
					{
						e.printStackTrace();
					}
				}

			}
		}

	}

方便快速开发的 注解框架基本原理 我理解就是这个了,下面是如何使用的问题,比较简单。

@ContentView(value = R.layout.activity_main)  //在类上加上注解 ,用来设置布局文件
public class MainActivity extends Activity implements OnClickListener  
{  
    @ViewInject(R.id.id_btn)   
    private Button mBtn1;   //在定义控件的字段成员上加上注解,用来初始化控件。
    @ViewInject(R.id.id_btn02)  
    private Button mBtn2;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
          
        ViewInjectUtils.inject(this);  //验证自定义的注解,也就是一些初始化工作等。

    }  

}
public static void inject(Activity activity)  
    {  
        injectContentView(activity);  
        injectViews(activity);  
        injectEvents(activity);  
    } 













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值