Android Java 动态代理应用

我当时勉强搞定其他那些反射方法,变量等等的时候,还不知道java动态代理是个什么东西,闻所未闻,只是实际工作中,遇见一个类似下面的东东,给难倒了:

onClickListener listener=new onClickListener(){

			@Override
			public void onClick() {
				// TODO Auto-generated method stub
				
			}
			
		};

一看这种形式怎么反射呀?刚开始看的时候在想,不就是反射onClickListener这个接口出来吗?但是问题来了,里面的onClick方法怎么弄呢?要在onClick里面添加自己的功能代码,按照前面的反射各种接口,还是方法,就是玩不出,后来想起了,看奇虎360公司的开源的360插件代码,但是并不是在代码中琢磨出来的,而是让我想起了我还有个老朋友在奇虎360公司做Android开发的,所以发了一个微信给他,结果很快他就告诉需要用到什么技术,而且给了下面的技术链接 :

https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/

看了之后,让人恍然醒悟,这个东西绝对是在整个反射中最神奇最牛逼的东西.有兴趣可以阅读以下上面链接的文章.

在正式下面使用代理之前,我还在考虑是不是写一个java回调方法的使用,大致举例说一下,也是我在博客园博客上面以前写的,通俗点如下:

用来干什么?

A问B一个问题,B一时想不出结果,A看B一时想不出结果,就对B说,想出结果了在告诉我,我顺便去做我的其他事情,做完事,你在告诉我你的结果.用程序实现如下:

<1> : 新建一个java工程,其中主类如下:

import callback.javaCallBackListener;
import out.waitToProblemSolved;

public class JavaCallBackTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        waitToProblemSolved wt=new waitToProblemSolved();
        //A开始告诉B要去解决问题了
        wt.doMyWorkWhenWait2Answer(new javaCallBackListener(){

            @Override
            public void toSolveProblem() {
                // TODO Auto-generated method stub B终于想去出结果了

                System.out.println("solver now have the answer !");
                
            }
            
        });
        
    }
    
}

<2> : A要发起问题:waitToProblemSolved.java:

package out;

import callback.javaCallBackListener;

public class waitToProblemSolved {

    public void doMyWorkWhenWait2Answer(javaCallBackListener listener) {

        // problemer could do work himself A自己开始做自己的事情
        System.out
                .println("problemer could do his work now until solver release his answer !");

        for (int i = 0; i < 3; i++) {

            System.out.println("problemer start to solve " + i + " work !");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            System.out.println("problemer finish his " + i + " work !");

        }
        
        // solver solve the answer B应该可以给出答案了
        listener.toSolveProblem();

    }

}

<3> : 解决问题者B:javaCallBackListener.java

package callback;

public interface javaCallBackListener {

    public void toSolveProblem();

}

大致就是上面的这个意思,为什么给出上面的demo,那是因为下面的代理其实托管接口的东东.

 

         具体Java动态代理理论可以写一本书了,建议关于理论方面参考网上的.

用到的主要类,Proxy.java

public static Object newProxyInstance(ClassLoader loader,

                      Class<?>[] interfaces,

                      InvocationHandler h)

                               throws IllegalArgumentException

 

第一个参数被代理类转载器;

第二个参数被代理类;

第三个参数是一个InvocationHandler

返回值为一个代理类的实例

public static InvocationHandler getInvocationHandler(Object proxy)
                                              throws IllegalArgumentException

 

返回代理类实例的InvocationHandler

http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html

其中上面InvocationHandler是一个接口,这个让代理处理被代理里面具体方法的实现.

Object invoke(Object proxy,
            Method method,
            Object[] args)
              throws Throwable

 

这个是InvocationHandler类必须让使用者必须实现的一个方法.

http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/InvocationHandler.html

下面通过一个具体例子介绍如何使用的:

<1> : 新建一个Java工程,工程树如下:

 

<2> : 首先先写一个接口类,onClickListener.java, 接口类中有三个方法需要实现,如下

package com.oneplus.interfaces;
/**
 * @author zhibao.liu
 * @date 2015-11-18
 * @company : oneplus.Inc
 */
public interface onClickListener {

	void onClick(int arg1,int arg2);
	int onSumClick(int arg1,int arg2);
	int onDulClick(int arg1,int arg2);
	
}

<3> : 然后写一个单独的类OneplusProxy,并且让其实现InvocationHandler接口:

package com.oneplus.invo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * @author zhibao.liu
 * @date 2015-11-18
 * @company : oneplus.Inc
 */
public class OneplusProxy implements InvocationHandler {

	private Object objs;

	public OneplusProxy(Object obj) {
		objs = obj;
	}

	@Override
	public Object invoke(Object object, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		Object result;
		int ret = 0;
		
		if(method.getName().equalsIgnoreCase("onDulClick")){
			
			if(args.length>1){
				
				ret=Integer.parseInt(args[0].toString())-Integer.parseInt(args[1].toString());
				
			}
			
			System.out.println("onDulClick  ret : "+ret);
			
			return ret;
			
		}
		
		for (int i = 0; i < args.length; i++) {

			System.out.println("Object args : " + args[i].toString());
			ret += Integer.parseInt(args[i].toString());

		}

		result = ret;

		System.out.println("oneplus method name : " + method.getName());

		return result;

	}

}


<4> : 然后在实现一个OneplusButton.java的类:

package com.oneplus.impl;

import com.oneplus.interfaces.onClickListener;
/**
 * @author zhibao.liu
 * @date 2015-11-18
 * @company : oneplus.Inc
 */
public class OneplusButton{

	private onChangeListener listener;
	private onClickListener clistener;
	private onClickListener slistener;
	private onClickListener dlistener;
	
	public interface onChangeListener{
		void onChanged();
	}
	
	public void setChangeListener(onChangeListener listener){
		
		System.out.println("setChangeListener ! ");
		
		this.listener=listener;
		listener.onChanged();
		
	}
	
	public void setClickedListener(onClickListener listener){
		
		clistener=listener;
		clistener.onClick(12, 23);
		
	}
	
	public Object setSumClickedListener(onClickListener listener){
		Object ret = null;
		
		return ret;
	}
	
	public Object setDulClickedListener(onClickListener listener,int arg1,int arg2){
		
		Object ret = null;

		
		return ret;
		
	}

	
}


<5> : 主类OneplusMainProxyClass.java,具体如下:

public static void ExcuteOnClick(){
		
		try {
			
			Class claimpl=Class.forName("com.oneplus.interfaces.onClickListener");
			
			InvocationHandler handler=new OneplusProxy(null);
			// 下面listener命名很有意思,让人直观感觉到了
// 代理了OnClickListener接口的一个对象
			Object listener=Proxy.newProxyInstance(claimpl.getClassLoader(), new Class<?>[]{claimpl}, handler);
			//下面再得到实施调用的类
/* 取名OneplusButton想UI控件,因为一般UI控件在设置事件的时候经常oneplusButton.setOnClickListener(new onClickListener(){
//TODO your work here
…
})
这里刚好,通过上面得到了listener,那么这个listener还需要这个UI控件通过setOnClickListener(listener)来调用,其实是实现了一个回调
 */
			Class clazz=Class.forName("com.oneplus.impl.OneplusButton");

			try {
				
				Object obj = null;
				try {
					obj = clazz.newInstance();
				} catch (InstantiationException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (IllegalAccessException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				/*
正如上面所说的,还需要反射出setClickedListener这个方法,用来消费listener
*/
				Method method=clazz.getDeclaredMethod("setClickedListener", claimpl);
				method.setAccessible(true);
				try {
					/*
调用setClickedListener方法,传入listener 
*/
					Object ret=method.invoke(obj, listener);
					if(ret!=null){
						System.out.println("main thread result : "+ret.toString());
					}
					
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}


程序大致理解如下:

<1> : 当执行Object ret=method.invoke(obj, listener);程序立即进入:

public void setClickedListener(onClickListener listener){
		
		clistener=listener;
		clistener.onClick(12, 23);
		
	}

<2> : 根据上面第一步, clistener.onClick(12, 23)程序执行到这一步,后面的onClick在哪里执行呢?这个就是程序:

Object listener=Proxy.newProxyInstance(claimpl.getClassLoader(), new Class<?>[]{claimpl}, handler);

开始由代理做下面的事情了,注意Proxy.newProxyInstance第三个参数handler,handler是一个实现InvocationHandler接口的类,那么就要实现接口的方法,而这个接口的方法:

public Object invoke(Object object, Method method, Object[] args)
			throws Throwable

正是用来处理onClick方法,从单个或者某种程度上来说invoke代理执行onClick的具体操作过程,onClick里面传递的两个参数,将会全部保存在invoke方法的第三个参数Object[] args,读者可以通过循环:

for(int i=0;i<args.lenght;i++){
System.out.println(“parameter “ +i+ ” value : ”+args[i].toString());
}

得到的结果分别是1223 , 这里面还有一个有意思的参数,那就是第二个参数,它居然还传递method下来,根据上面具体程序,可以打印这个method的名称:

Objectobject=method.getName();

这样获取的名字是:onClick,这个方法名也返回在以后中可能因为还需要继续反射使用,例如method.invoke(object,args).

那么为什么invoke只是在某种程度上执行的就是onClick方法,那是因为如果接口只有一个方法或者只需要代理这一个,就可以勉强这样理解,其实如果onClickListener类有多个方法需要实现时,那么invoke会一个一个的帮助你完成.当然同样,即使是同一个接口onClickListener也可以用不同InvocationHandler分别处理.

<3> : 同理,继续在OneplusButton类中实现:

public Object setSumClickedListener(onClickListener listener){
		
		Object ret;
		
		slistener=listener;
		ret=slistener.onSumClick(11, 32);
		
		return ret;
	}
	
	public Object setDulClickedListener(onClickListener listener,int arg1,int arg2){
		
		Object ret = null;
		
		dlistener=listener;
		
		ret=dlistener.onDulClick(arg1, arg2);
		
		return ret;
		
	}


<4>: 在主类中添加如下:

public static void ExcuteOnDulClick(){
		
		try {
			
			Class claimpl=Class.forName("com.oneplus.interfaces.onClickListener");
			
			InvocationHandler handler=new OneplusProxy(null);
			
			Object listener=Proxy.newProxyInstance(claimpl.getClassLoader(), new Class<?>[]{claimpl}, handler);
			
			Class clazz=Class.forName("com.oneplus.impl.OneplusButton");
			
			try {
				Object obj=clazz.newInstance();
				
				try {
					Method method=clazz.getDeclaredMethod("setDulClickedListener", claimpl,int.class,int.class);
					
					try {
						Object ret=method.invoke(obj, new Object[]{listener,102,201});
						System.out.println("3 type main thread ret : "+ ret.toString());
					} catch (IllegalArgumentException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				} catch (NoSuchMethodException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SecurityException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public static void ExcuteOnSumClick(){
		
		try {
			
			Class claimpl=Class.forName("com.oneplus.interfaces.onClickListener");
			
			InvocationHandler handler=new OneplusProxy(null);
			
			Object listener=Proxy.newProxyInstance(claimpl.getClassLoader(), new Class<?>[]{claimpl}, handler);
			
			Class clazz=Class.forName("com.oneplus.impl.OneplusButton");
			
			try {
				Object obj=clazz.newInstance();
				
				try {
					Method method=clazz.getDeclaredMethod("setSumClickedListener", claimpl);//第二个是传递的参数类型,经常忘记!
					try {
						Object ret=method.invoke(obj, listener);
						
						System.out.println("main thread ret : "+ ret.toString());
						
					} catch (IllegalArgumentException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} catch (NoSuchMethodException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SecurityException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}



注意:可以从上面来看,还能够实现返回值等

上面的方法调用如下 :

public static void main(String[] args) {
		// TODO Auto-generated method stub
		ExcuteOnChange();
		
		ExcuteOnClick();
		
		ExcuteOnSumClick();
		
		ExcuteOnDulClick();
		
	}


最终执行的结果如下 :









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值