Android学习笔记:Android客户端采用Hessian进行异步请求

本文介绍了在Android客户端中使用Hessian框架进行网络请求,并结合异步处理的实现方法。通过HessianNewProxy和HessianAsynTask,实现了在Android和Java项目中统一的异步任务执行,利用HessianAsynTaskExecuter接口允许用户自定义线程执行方式,确保在方法执行前后进行特定操作。详细流程包括登录请求、任务执行观察器和监听器的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

日前,做了一个小练习,采用的hessian框架实现的网络访问,其中在传统的hessian网络访问请求中加入了一些异步的元素。如下图为传统的hessian请求的简略图

我们以登录为例,来看看代码的流程:

请求:

接口中阻塞式登录方法,自己代码:

/**登录--登录**/
	public User login(String userName,String passWord,long id,int typeId) throws InteractionException;

 

产生通过HessianProxyFactory产生HessianProxy的方法,看源码:

public Object create(Class<?> api, URL url, ClassLoader loader)
  {
    if (api == null)
      throw new NullPointerException("api must not be null for HessianProxyFactory.create()");
    InvocationHandler handler = null;

    handler = new HessianProxy(url, this, api);

    return Proxy.newProxyInstance(loader,
                                  new Class[] { api,
                                                HessianRemoteObject.class },
                                  handler);
  }


得到HessianProxy以后,调用里面的invoke方法即login的代理方法实现登录简单的请求,看源码。

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

        ....... 

      AbstractHessianOutput out = _factory.getHessianOutput(os);

      out.call(methodName, args); //将登录方法名和参数写出去
      out.flush();

        ........

  }


通过得到的HessianProxy直接调用第一步中的login方法即可,自己代码:

proxy.login("duancanmeng","123");

 

在上面的基础假如一些异步的元素,

如何来体现异步性?

无非就是开线程,那到底该如何开呢?在哪里开呢?开什么样的线程?

首先想到的应该就是把HessianProxy中的invoke放入新开的线程中处理,这是最基本的。直接new Thread行吗?

当然可以,于是可以写一个类HessianNewProxy继承HessianProxy,复写invoke方法,这里面可以做一些检查,如果判断是异步的,则在新开的线程中调用父类的invoke方法,否则,直接在主线程中调用父类的invoke方法:

HessianNewProxy:

invoke(){

    if(异步){

        new Thread(){

            run(){

                 super.invoke();

            }

        }.start();

    }else{

        super.invoke();

    }

}

可是在android中并不推荐直接new Thread来执行异步请求(考虑到一些界面刷新的问题),android内部封装了自己的异步任务类AsynTask。可是普通的java项目却并没有如此的异步任务类,要想实现普通java项目也能和android项目一样,在方法执行前和执行后都做一些操作的话,在这里,我们可以把线程实现的方式作为接口抽出来交给用户自己实现,于是,在invoke的异步块中,用异步任务执行器来执行异步任务,但是具体的实现方式交给用户视情况处理。上面的代码可以改成:

invoke(){

    if(异步){

        自己视情况的线程方式(HessianAsynTask task);

    }else{

        super.invoke();

    }

}

 

其中HessianAsynTask:

package com.pccw.hessian.support.client;

/**
 * 任务执行监听器.
 * 该监听器只应该在UI线程中创建
 * @param <R>	任务成功执行返回结果类型
 * @param <E>	任务执行抛出的异常类型
 */
public interface HessianAsynTask<R,E extends Throwable> {
	
	R doInBackground() throws E;

	/**
	 * 任务执行过程中出现异常将调用此方法
	 * [执行在UI线程]
	 */
	void onExceptionOccured(E e);
	/**
	 * 任务执行成功将调用该方法,Result是任务结果
	 */
	void onExecuteSuccess(R result);
	
	/**
	 * 任务成功执行[或者发生异常]后都将执行该方法
	 * @param context
	 * @param uriKey
	 */
	void onFinally(R result);
}

这样的话我们只需要在自己实现的线程方式中,控制HessianAsynTask中方法执行的顺序,则既照顾到了android项目,也照顾到了java项目。而线程的实现方式如何交给用户自己实现?这里也需要定义一个异步任务执行器的接口HessianAsynTaskExecuter,其代码如下:

HessianAsynTaskExecuter:

package com.pccw.hessian.support.client;

/**
 *  异步任务执行器
 *
 */
public interface HessianAsynTaskExecuter<R,E extends Throwable> {
	
	public void execute(HessianAsynTask<R,E> executer);
	
}

那么,前面HessianNewProxy中invoke方法可以改为:

invoke(){

    if(异步){

        HessianAsynTaskExecuter.execute(HessianAsynTask);

    }else{

        super.invoke();

    }

}


我们只关心异步任务执行器的实现即可,如此一来,不论android项目还是java项目,在调用真正业务方法之前或者之后的一些操作,都统一在HessianAsynTask中可以处理了。

比如,我如果是java项目,我可以在HessianAsynTaskExecute的实现类中可以new Thread来控制HessianAsynTask中方法的实现顺序来达到前置和后置操作:

execute(HessianAsynTask task){
    new Thread(){
	try{
	    task.doInBackground(){
	        login();
	    };
	    task.onExecuteSuccess();
	}
	}catch(){
 	    task.onExceptionOccured();
 	}finally{
	    task.onFinally();
	}
    }
}


如果是android项目,则如下:

execute(final HessianAsynTask<R,E> executer) {
		new AsyncTask<Void, Void, Exception, R>(){
			@Override
			protected R doInBackground(Void... params) throws Exception {
				return executer.doInBackground();
			}
			@Override
			protected void onPostExecute(R result) {
				executer.onExecuteSuccess(result);
				executer.onFinally(result);
			}
			@SuppressWarnings("unchecked")
			@Override
			protected void onExceptionOccured(Exception e) {
				executer.onExceptionOccured((E) e);
				executer.onFinally(null);
			}			
		}.execute();
	}
}

因此可以看出HessianAsynTaskExecute是结合HessianAsynTask配套使用来适应不同的情况。

具体的流程看如下图:

HessianAsynTaskExecuter:异步任务执行器,用来执行请求中传过来的异步任务,比如异步登录

HessianTaskExcuterObserver:任务执行观察器,用来监视任务(包括异步和非异步的任务)的执行情况,其中可以做一些缓存、资源等处理

HessianAsynTask:异步任务,主要结合HessianAsynTaskExecuter使用,作为参数传入执行器的方法中用来执行。

TaskExecuteListener:任务执行监听器,监听异步任务的执行情况,其中可以做一些缓存、资源的处理等

 

1、登录请求

      接口中阻塞式登录方法:

/**登录--登录**/
	public void login(String userName,String passWord,long id,int typeId,TaskExecuteListener<User, InteractionException> listener);

 

2、factory产生proxy。

remoteService = proxyFactory.create(RemoteService.class, url, 
				new CMSAsynTaskExecuter<Object, Exception>(),
				new CMSExceptionHandler(),
				new CMSTaskExcuterObserver(SharedPreferencesUtlis.getAppSharedPreferences(context)),
				new CMSConnectionObserver(SharedPreferencesUtlis.getAppSharedPreferences(context)));
		

 

3、判断是否为异步请求,这里通过login方法中的参数来判断,如果是异步,则里面传入一个TaskExecuteListener。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
		mTaskExecuteObserver.onPerExecute(this,proxy,method, args);

		/**
		 * =========================================异步任务块
		 */
		TaskExecuteListener<Object,Throwable> taskExecuteListener=null;
		if(args!=null && args.length > 0 && args[args.length-1] instanceof TaskExecuteListener){//检测该方法是否为异步方法,检测的依据是改方法的参数列表中最后一个参数类型是TaskExecuteListener
			taskExecuteListener=(TaskExecuteListener<Object,Throwable>) args[args.length-1];
			args=SupportUtils.copyOfRange(args, 0, args.length-1);
			method=getNoAsynMethod(method);//将方法和参数都换成非异步的方法和参数
			taskExecuteListener.onPerExecute(method, args);
		}
		
				
		if(taskExecuteListener!=null){//如果需要向远程获取数据且发现为异步任务,那么启动异步方法执行任务,本方法直接返回null
			doInvokeAsyn(proxy, method, args,taskExecuteListener);
			return null;
		}else{//直接阻塞式向远程服务端请求数据
			Object result=null;
			Throwable e=null;
			try {
				 result=super.doInvoke(proxy, method, args);
				 mTaskExecuteObserver.onExecuteSuccess(this,proxy,method, args, result);
				return result;
			} catch (Throwable e1) {
				e=exceptionHandler.parseException(e1);
				Object secondResult=mTaskExecuteObserver.onExceptionOccured(this,proxy,method, args, e);//如果异常挽救措施成功那么该任务仍是成功的
				 mTaskExecuteObserver.onExecuteSuccess(this,proxy,method, args, secondResult);
				return secondResult;
			}finally{
				mTaskExecuteObserver.onFinally(this,proxy,method, args, result,e);
			}
		}
	}
	
	


4、通过异步任务执行器执行异步任务

@SuppressWarnings("unchecked")
	private void doInvokeAsyn(final Object proxy, final Method method, final Object[] args,final TaskExecuteListener<Object,Throwable> taskExecuteListener){
		((HessianNewProxyFactory)_factory).getAsynTaskExecuter().execute(new HessianAsynTask<Object,Throwable>() {
			private Throwable mThrowable;
			private Object mResult;
			@Override
			public Object doInBackground() throws Throwable {
				return doInvoke(proxy, method, args);
			}
			@Override
			public void onExceptionOccured(Throwable exception) {
				exception=exceptionHandler.parseException(exception);
				Object result=null;
				try {
					result=mTaskExecuteObserver.onExceptionOccured(HessianNewProxy.this,proxy, method, args, exception);
					onExecuteSuccess(result);
				} catch (Throwable e) {
					mThrowable=e;
					taskExecuteListener.onExceptionOccured(method, args, e);
				}
			}
			@Override
			public void onExecuteSuccess(Object result) {
				mResult=result;
				mTaskExecuteObserver.onExecuteSuccess(HessianNewProxy.this,proxy, method, args, result);
				taskExecuteListener.onExecuteSuccess(method, args, result);
			}
			@Override
			public void onFinally(Object result) {
				mTaskExecuteObserver.onFinally(HessianNewProxy.this,proxy, method, args, mResult, mThrowable);
				taskExecuteListener.onFinally(method, args, mResult);
			}
		});
		
	}
	
}

5,6、HessianAsynTask在第四步中的代码可以看出是作为一个参数传入,同时这个参数中还需要一个监听器参数TaskExecuteListener,TaskExecuteListener只是针对异步请求的监听而且范围很小,只是针对该请求,TaskExecuteListener代码如下:

/**
 * 任务执行监听器.
 * 该监听器只应该在UI线程中创建
 * @param <T>	任务成功执行返回结果类型
 */
public interface TaskExecuteListener<R,E extends Throwable> {
	
	/**
	 * 在任务开始前执行该方法,你可以在此方法做一些初始化工作
	 * [执行在UI线程]
	 */
	void onPerExecute(Method method, Object[] args);
	/**
	 * 任务执行过程中出现异常将调用此方法
	 * [执行在UI线程]
	 */
	void onExceptionOccured(Method method, Object[] args,E e);
	/**
	 * 任务执行成功将调用该方法,Result是任务结果
	 */
	void onExecuteSuccess(Method method, Object[] args,R result);
	
	/**
	 * 任务成功执行[或者发生异常]后都将执行该方法
	 * @param context
	 * @param uriKey
	 */
	void onFinally(Method method, Object[] args, R result);
}


7、HessianTaskExcuterObserver是一个整体的监听器,针对任何请求方法,而且不论是异步还是非异步的,里面可以做一些缓存的设置,比如在很久不进行操作之后,然后获取数据之前判断缓存中是否有登陆用户的信息,如果有,则进行获取数据,如果没有,则进行登录。

具体代码:


public interface HessianTaskExcuterObserver {
	
	/**
	 * 在任务开始前执行该方法,你可以在此方法做一些初始化工作
	 * [执行在UI线程]
	 */
	void onPerExecute(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args);
	
	/**
	 * 在任务执行前进行一些检测
	 * @return 如果为true则没有问题,继续执行,如果为false则检测有问题,停止执行并执行onCheckFalseReturn
	 */
	boolean onPerExecuteCheck(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args);
	
	/**
	 * 在任务执行前进行一些检测, 如果为false则检测有问题,则执行onCheckFalseReturn并且任务停止执行
	 */
	Object	onCheckFalseAndReturn(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args);
	
	/**
	 * 任务执行过程中出现异常将调用此方法
	 * @return 你可以在此方法中继续throw e,但是你仍有机会返回合适的任务执行结果 
	 */
	Object onExceptionOccured(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args,Throwable e) throws Throwable;
	/**
	 * 任务执行成功将调用该方法,Result是任务结果
	 */
	void onExecuteSuccess(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args,Object result);
	
	/**
	 * 任务成功执行[或者发生异常]后都将执行该方法
	 */
	void onFinally(HessianProxy InvocationHandler,Object proxy,Method method, Object[] args, Object result,Throwable e);
}

该包的源码的下载地址:http://download.youkuaiyun.com/detail/duancanmeng/4561246

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值