編輯:關於Android編程
“什麼是spring aop?”,我頓時大腦浮想聯翩,我想到了事物管理、SDK、代碼監控、spring remoting,這麼多東西,我從哪裡回答呢,後來變得大腦一片空白,這提問有問題啊,aop在我腦子裡面有那麼多表現形式,你如果提出一個功能,問我怎麼做,我肯定不會思維混亂的,本來aop就夠抽象了,你還問的這麼抽象。
“你用過aop嗎“
用過,我在給android的服務端接口SDK裡面用過的。android在調用服務端api的時候要對本地方法進行攔截,並且把最終實現邏輯加上http調用的代碼...。
這跟aop有什麼關系?
好吧,沒什麼關系。但明白人說呢,到底有沒有關系?
下面我來解釋一下看看,大家給評評理。
這次我先說一下android遠程api調用SDK的實現方式。
舉例,修改密碼的功能。在沒有sdk之前一般都這麼寫的
User user = new User(); user.setPassword(password); HttpClient client = new HttpClient(); client.remoteUrl = “http://a.com/user/modifyPassword” client.params = JSON.toJsonString(user); String response = client.invokeUrl(); ServiceInvokeResult result = JSON.parse(response ,ServiceInvokeResult .class); If(result.status == ‘200’ && result.resultMessage == ‘success’){ System.out.println(‘修改成功’); }
這麼寫沒啥不行的,但我認為有幾個問題:
1.第2、3、4、5、6行的代碼,在涉及到其他的服務端接口調用的地方都需要寫的。
2.Android程序員必須知道remoteUrl怎麼寫,實際上他並不關心這玩意的
3.Android需要處理參數、返回值序列化
實際上上面幾個問題可以歸納為:android程序員想少些代碼。
那麼代碼能否改成這樣呢
User user = new User(); user.setPassword(password); InvokeResult result = userService.modifyPassword();
看起來像是調用一個本地的方法,而且這樣至少能少寫4行代碼吧,可能有些人會說:這算個鳥,我們開發程序最主要的目的是快速完成任務,有那時間復制粘貼早搞定了,思考那麼多浪費時間。
如果你是這種思想的話,那就看到這裡為止吧。下面的內容不是給你看的,有興趣的可以往下面看。
有人說把少寫的那些代碼放到modifyPassword()裡面不就完了嗎,呵呵。我會說,“dont’t give me your suit,you know i mean that”.
怎麼寫才能讓調用本地方法擁有調用遠程服務的能力。我們實際上是在修改方法的實現邏輯
仔細觀察每一個包含遠程調用的實現代碼,我們可以發現,這類代碼都有包含下面的邏輯
進一步講,我們應該把組裝參數,發起http請求和獲取請求的返回值提取到一個公共的地方,並且讓每一個實現代碼自動去調用,如何實現這個自動。
我們都聽說過AOP,那再去看看這篇文檔http://shouce.jb51.net/spring/aop.html
看完後有我感覺沒有頓時豁然開朗的感覺,不能馬上感覺到與我們要解決的問題有什麼關系,而是睡著了,這是他媽誰寫的玩意,看了讓老子想睡覺。
我用我自己能理解的語言來解釋一下:AOP像是一個監視系統,他能監視你的代碼執行,並且根據你的需求在你代碼執行之前、執行之後、拋異常的時候做出反應,他的核心是代理,最終運行的是代理類,而不是你自己寫的類。
你的代碼把組裝參數發起http請求、獲取請求的返回值代理給代理類處理
AOP代理分為靜態代理和動態代理,靜態代理指的是在編譯期生成代理類,一般用命令生成,像AspectJ,它的邏輯是用它的命令修改了生成的class,你可以把class用反編譯工具打開查看,裡面有很多它生成的代碼。而動態代理是在運行時在內存中生成代理類。
不像服務端程序,你想引入什麼類庫就引入什麼類庫,在android這種環境中,盡量不要引入第三方類庫,因為那是要打包進去的,增加apk的體積。接下來,我們用jdk自帶的動態代理來實現。
Java創建代理類是通過java.lang.reflect.Proxy的newProxyInstance方法來完成的,這個方法有三個參數
ClassLoader loader:代理類的類加載器
Classinterfaces: 代理類要實現的接口,最終會產生一個代理類名字是 $ProxyN(N=1-65535),這個代理類要實現這些接口
InvocationHandler h:實現了InvocationHandler接口的類
這裡面有一些要求:
1.要代理的類必須用接口的形式。
為啥?
規范呗,java不是一直在說面向接口編程嗎。
那我告訴你CGLIB沒這個要求。
啥B,那就是那啥B不規范呗...
我來告訴你吧,newProxyInstance生成的代理類都繼承了Proxy,java又不允許多繼承,但是可以多實現。
哦,明白了,只能繼承一個,那我先把這個坑占了。那我明白了又能怎樣,你告訴我,我明白了這玩意能漲工資不?
......
2.你需要提供一個實現了InvocationHandler 的類,在這個類裡面做你的邏輯,比如把組裝參數,發起http請求和獲取請求的返回值等相關代碼放進去。
那就動手寫起來呗,我們先來寫一個InvocationHandler 實現類,這個類是抽象的,因為有可能有多種用途的實現類,代碼看起來像下面的樣子
import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.Type; public abstract class ProxyFactoryimplements InvocationHandler { private Class targetClass; private String targetClassName; private String methodName; public String getTargetClassName() { return targetClassName; } public String getMethodName() { return methodName; } public ProxyFactory(Class clazz){ super(); this.targetClass = clazz; } public M getProxy(){ return (M) Proxy.newProxyInstance(targetClass.getClassLoader(), new Class[]{targetClass}, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; try { //獲取方法名 this.methodName = method.getName(); //獲取參數名 String[] argNames = Classes.parseMethodVarNames(method); before(argNames, args); this.targetClassName = targetClass.getName(); result = after(method.getGenericReturnType()); } catch (Exception e) { onException(e); } return result; } public abstract void onException(Exception ex); public abstract Object after(Type type); public abstract void before(String[] argNames,Object[] args); }
InvocationHandler 只有一個方法invoke,在這裡面傳入,代理類,代理類的方法,方法的參數值。
我們另外定義3個方法以備後用,分別代表before(方法調用之前邏輯)、after(方法調用後邏輯),onException(方法拋異常邏輯)。
我們再定義一個用來做遠程調用的實現類,如下
import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; public class RemoteProxyextends ProxyFactory { private HTTPClient client = new HTTPClient(); private Map map = new HashMap (); public RemoteProxy putOtherParameters(String parameterName,Object parameterValue){ map.put(parameterName,parameterValue); return this; } public RemoteProxy(Class clazz){ super(clazz); } @Override public void onException(Exception ex){ ex.printStackTrace(); } @Override public Object after(Type returnType) { String serviceUri = Classes.parseClassMethodToUri(super.getTargetClassName(), super.getMethodName()); client.setServiceUri(serviceUri); String responseStr = client.request(); return Classes.stringToObject(responseStr,returnType); } @Override public void before(String[] argNames, Object[] args) { map.clear(); for(int i = 0;i < argNames.length;i ++){ String argName = argNames[i]; map.put(argName,args[i]); } client.setParams(map); } }
在before的實現裡面,我們組裝參數。在after中我們設置調用的服務端url,進行遠程調用,接著反序列化服務端的返回值。
假設你要代理UserService的接口,那麼我們通過下面的代碼去創建一個UserService的代理對象,並且調用相關業務方法
UserService userService = new RemoteProxy(UserService.class).getProxy(); userService.modifyPassword();
網上說AOP是面向方面、切面編程,那麼我們通過上面的例子可以看出before、onException、after就是AOP提供給我們的方面、切面的某種表現形式,明白了嘛?
沒明白!
......
那我抽時間再弄點別的例子吧。
原生的Toolbar基本的功能樣式已經在上節簡單的說了一下,但是當前的樣式並不滿足我們的需要,因此這一節主要探索一下Toolbar的一些內容上調整的方法,比如Title位
listview實現上拉加載以及下拉刷新的方式有很多。下面是我寫的一種自定義的布局,復用性也比較的強。首先就是繼承的listview的自定義view。 &nbs
一.寫在前面的話在日常使用手機的過程中,我們經常希望有這樣一個功能:可以對我們的某一個應用加鎖,進入的時候需要輸入密碼驗證身份,然後才可以進入主界面,這就是一個程序鎖的功
百度了下,好像都沒找到想要的,或許是我百度錯了關鍵字吧。我這就介紹一種我現在剛學的方法。首先web端費給我們一個接口文檔。我這就接觸到兩塊內容:(1)通過接口傳遞單純的數