Android學習筆記:Android用戶端採用Hessian進行非同步請求

來源:互聯網
上載者:User

日前,做了一個小練習,採用的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>(){@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:任務執行監聽器,監聽非同步任務的執行情況,其中可以做一些緩衝、資源的處理等

 

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.