編輯:關於Android編程
一、前言
最近學習http框架。
目前寫的這個框架暫時只適用於學習之用,實際用於項目之中還需要不斷的優化。
要從服務器或者網絡獲取數據,顯示到UI上面,網絡請求的操作不能放在UI線程中進行,android為我們封裝了AsyncTask類來進行異步的請求操作,所以這個Http框架基於AsyncTask。
二、框架主要類
定義Request類,定義url,服務器返回數據,post的請求params,下載進度等參數。
定義HttpUtil類來封裝http請求代碼。在裡面定義execute()方法,該方法判斷是get還是post,然後再去call get(),post() 方法。post() 請求需要的參數在Request中設置.
在AsyncTask中,doingBackground()方法中 execute http,將返回的數據寫到內存中變成String返回,如果數據較大,可以先存到文件中,把path返回,在不同的callback中處理。
三、框架搭建
1. 首先,我們建立 HttpClientUtil.java 類,用於處理HTTP的get和post,裡面定義execute()方法,該方法判斷是get還是post,然後再去call get(),post() 方法,post() 請求需要的參數在Request中設置.:
/** * @author Mr.傅 */ public class HttpClientUtil { /** * 執行HTTP方法,Request 設置請求類型 * @param request * @return * @throws Exception */ public static HttpResponse excute(Request request) throws Exception{ switch (request.requestMethod) { case GET: return get(request); case POST: return post(request); default: //這裡沒有定義 DELETE 和 PUT 操作 throw new IllegalStateException("you doesn't define this requestmethod"); } } private static HttpResponse get(Request request) throws Exception { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(request.url); addHeader(get, request.headers); //返回的結果放到上一層進行處理 HttpResponse response = client.execute(get); return response; } private static HttpResponse post(Request request) throws Exception { HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost(request.url); addHeader(post, request.headers); //post的請求參數在 Request 中定義,如果為空,則沒有定義 if (request.entity == null) { throw new IllegalStateException("you forget to set post content to the httpost"); }else { post.setEntity(request.entity); } HttpResponse response = client.execute(post); return response; } /** * 請求頭 * @param request * @param headers */ public static void addHeader(HttpUriRequest request, Map2. 上述代碼中的 Request.java 類,定義url,服務器返回數據,post的請求params,下載進度等參數定義如下:headers){ if (headers != null && headers.size() > 0 ) { for(Entry entry : headers.entrySet()){ request.addHeader(entry.getKey(), entry.getValue()); } } } }
/** * @author Mr.傅 */ public class Request { public enum RequestMethod{ GET,POST,DELETE,PUT } RequestMethod requestMethod; public String url; /** * Http請求參數的類型,包括表單,string, byte等 */ public HttpEntity entity; public Map3. ICallback接口,該接口的onFilure和onSuccess方法在UI線程當中實現,如果在RequestTask中doInBackground中HttpResponse返回成功則在onPostExecute中調用onSuccess,否則調用onFilure,並傳遞已經解析了的返回參數:headers; public static final String ENCODING = "UTF-8"; /** * 設置回調接口,該接口中的onSuccess和onFilure方法需要在體現在UI線程當中 */ public ICallback callback; private RequestTask task; public Request(String url, RequestMethod method) { this.url = url; this.requestMethod = method; } public void setEntity(ArrayList forms){ try { entity = new UrlEncodedFormEntity(forms, ENCODING); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } public void setEntity(String postContent){ try { entity = new StringEntity(postContent, ENCODING); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } public void setEntity(byte[] bytes){ entity = new ByteArrayEntity(bytes); } /** * 設置回調方法,在ui線程中定義需要請求 返回的 方法 * @param callback */ public void setCallback(ICallback callback) { this.callback = callback; } /** * UI線程中,執行該方法,開啟一個AsyncTask,注意AsyncTask每次使用必須重新new */ public void execute() { task = new RequestTask(this); task.execute(); } }
public interface ICallback { void onFilure(Exception result); void onSuccess(Object result); /** * 將從服務器得到的HttpResponse進行解析,解析完成以後,返回給UI線程 */ Object handle(HttpResponse response); }
4. RequestTask 繼承自 AsyncTask ,在doInBackground 進行HTTP請求,同時對HTTP請求返回的數據結果進行解析,通過調用callback中的handle方法,解析HTTP請求返回的參數,返回後的結果(如果拋出異常,將異常也返回),在onPostExecute中進行處理,調用不同的方法,返回到UI線程,代碼如下:
/** * @author Mr.傅 * @version create time:2014年5月17日 下午2:19:39 */ public class RequestTask extends AsyncTask5. AbstractCallback.java 該類 中實現接口 ICallback 的 handle 方法,該方法主要作用是,對HTTP返回的HttpResponse 進行解析,如果返回狀態碼是200,則進行下一步處理;如果UI調用了setPath()方法,設置了保存的路徑的話,就將HTTP返回的數據先寫入到文件中,然後文件中讀取出來,放入到對應的解析實現類中,如:StringCallback,JsonCallback等, 返回到doInBackground 中(doInBackground 中的return request.callback.handle(response)步驟)。如果沒有設置路徑,則直接調用bindData(EntityUtils.toString(entity)),
/** * @author Mr.傅 */ public abstract class AbstractCallback implements ICallback{ /** * 文件存放的路徑 */ public String path; private static final int IO_BUFFER_SIZE = 4*1024; @Override public Object handle(HttpResponse response){ // file, json, xml, image, string int statusCode = -1; InputStream in = null; try { HttpEntity entity = response.getEntity(); statusCode = response.getStatusLine().getStatusCode(); switch (statusCode) { case HttpStatus.SC_OK: if (TextUtil.isValidate(path)) { //將服務器返回的數據寫入到文件當中 FileOutputStream fos = new FileOutputStream(path); if (entity.getContentEncoding() != null) { String encoding = entity.getContentEncoding().getValue(); if (encoding != null && "gzip".equalsIgnoreCase(encoding)) { in = new GZIPInputStream(entity.getContent()); } if (encoding != null && "deflate".equalsIgnoreCase(encoding)) { in = new InflaterInputStream(entity.getContent()); } } else { in = entity.getContent(); } byte[] b = new byte[IO_BUFFER_SIZE]; int read; while ((read = in.read(b)) != -1) { // TODO update progress fos.write(b, 0, read); } fos.flush(); fos.close(); in.close(); //寫入文件之後,再從文件當中將數據讀取出來,直接返回對象 return bindData(path); } else { // 需要返回的是對象,而不是數據流,所以需要去解析服務器返回的數據 // 對應StringCallback 中的return content; //2. 調用binData return bindData(EntityUtils.toString(entity)); } default: break; } return null; } catch (ParseException e) { //這些異常處理都沒有進行操作,後面的文章會再做處理 } catch (IOException e) { } return null; } /** * 數據放入到不同的Callback中處理 */ protected Object bindData(String content){ //StringCallback等方法中實現了該方法 return null; } /** * 如果要存入到文件,則設置文件路徑 */ public AbstractCallback setPath(String path){ this.path = path; return this; } }6. StringCallback.java 目前的代碼,只實現了該callback,JsonCallback,PathCallback,會在後面的文章當中具體實現:
public abstract class StringCallback extends AbstractCallback { @Override protected Object bindData(String content) { //如果路徑存在,則重新講數據從文件中讀取出來 if (TextUtil.isValidate(path)) { return IOUtiliteies.readFromFile(path); } return content; } }7. 當中用到的TextUtil.java 類
public class TextUtil { public static boolean isValidate(String content){ return content != null && !"".equals(content.trim()); } public static boolean isValidate(ArrayList8. UI線程中具體調用方法如下:content){ return content != null && content.size() > 0; } }
private void requestString() { //設置保存路徑 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "mrfu_http.txt"; Request request = new Request("http://www.baidu.com", RequestMethod.GET); request.setCallback(new StringCallback() { @Override public void onSuccess(Object result) { mTestResultLabel.setText((String)result); } @Override public void onFilure(Exception result) { result.printStackTrace(); } }.setPath(path)); request.execute(); }
其中mTestResultLabel 是TextView
可以看到實現效果,這裡我們在SD卡的根目錄下將返回結果存入到了 "mrfu_http.txt" 文件中,同時顯示到了 UI 上面:如圖所示:
源碼下載:http://download.csdn.net/detail/fu222cs98/7377683
我將模擬器解壓到C:\android-sdk-windows\在C:\android-sdk-windows\platform-tools這個文件夾裡有個a
本文實例講解的是如何畫一個滿滿圓形水波紋loadingview,這類效果應用場景很多,比如內存占用百分比之類的,分享給大家供大家參考,具體內容如下效果圖如下:預備的知識:
前言現在的APP大部分需要接入支付功能,而支付的主流就是微信支付和支付寶支付,網上關於微信支付和支付支付資料很多,但是這些資料隨著官方的變動可能變得毫無用處,所以我建議直
Tips:此源碼分析基於Android 4.2先來看看一個Activity上的UI控件結構: 圖1-1 Activity中的UI組件結構好了現在開