首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

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

2012-09-20 
Android学习笔记:Android客户端采用Hessian进行异步请求日前,做了一个小练习,采用的hessian框架实现的网络

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

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

Android学习札记:Android客户端采用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>(){@Overrideprotected R doInBackground(Void... params) throws Exception {return executer.doInBackground();}@Overrideprotected void onPostExecute(R result) {executer.onExecuteSuccess(result);executer.onFinally(result);}@SuppressWarnings("unchecked")@Overrideprotected void onExceptionOccured(Exception e) {executer.onExceptionOccured((E) e);executer.onFinally(null);}}.execute();}}

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

具体的流程看如下图:

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

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

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

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

 

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

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){//检测该方法是否为异步方法,检测的依据是改方法的参数列表中最后一个参数类型是TaskExecuteListenertaskExecuteListener=(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){//如果需要向远程获取数据且发现为异步任务,那么启动异步方法执行任务,本方法直接返回nulldoInvokeAsyn(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;@Overridepublic Object doInBackground() throws Throwable {return doInvoke(proxy, method, args);}@Overridepublic 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);}}@Overridepublic void onExecuteSuccess(Object result) {mResult=result;mTaskExecuteObserver.onExecuteSuccess(HessianNewProxy.this,proxy, method, args, result);taskExecuteListener.onExecuteSuccess(method, args, result);}@Overridepublic 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并且任务停止执行 */ObjectonCheckFalseAndReturn(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.csdn.net/detail/duancanmeng/4561246

热点排行