Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android學習之——自己搭建Http框架(1)

Android學習之——自己搭建Http框架(1)

編輯:關於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, Map headers){
		if (headers != null && headers.size() > 0 ) {
			for(Entry entry : headers.entrySet()){
				request.addHeader(entry.getKey(), entry.getValue());
			}
		}
	}
}
2. 上述代碼中的 Request.java 類,定義url,服務器返回數據,post的請求params,下載進度等參數定義如下:
/** 
 * @author Mr.傅
 */
public class Request {
	public enum RequestMethod{
		GET,POST,DELETE,PUT
	}
	RequestMethod requestMethod;
	public String url;
	/**
	 * Http請求參數的類型,包括表單,string, byte等
	 */
	public HttpEntity entity;
	public Map 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();
	}
}
3. ICallback接口,該接口的onFilure和onSuccess方法在UI線程當中實現,如果在RequestTask中doInBackground中HttpResponse返回成功則在onPostExecute中調用onSuccess,否則調用onFilure,並傳遞已經解析了的返回參數:
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 AsyncTask {
	private Request request;

	public RequestTask(Request request) {
		super();
		this.request = request;
	}
	@Override
	protected Object doInBackground(Object... params) {
		try {
			HttpResponse response = HttpClientUtil.excute(request);
			//response 解析代碼放到對應的類中,對應handle中的bindData方法
			return request.callback.handle(response);
		} catch (Exception e) {
			return e;
		}
	}

	@Override
	protected void onPostExecute(Object result) {
		super.onPostExecute(result);
		if (result instanceof Exception) {//失敗
			request.callback.onFilure((Exception)result);
		}else {//成功
			request.callback.onSuccess(result);
		}
	}
}
5. AbstractCallback.java 該類 中實現接口 ICallback 的 handle 方法,該方法主要作用是,對HTTP返回的HttpResponse 進行解析,如果返回狀態碼是200,則進行下一步處理;如果UI調用了setPath()方法,設置了保存的路徑的話,就將HTTP返回的數據先寫入到文件中,然後文件中讀取出來,放入到對應的解析實現類中,如:StringCallback,JsonCallback等, 返回到doInBackground 中(doInBackground 中的return request.callback.handle(response)步驟)。如果沒有設置路徑,則直接調用bindData(EntityUtils.toString(entity)),
放入到具體的Callback中進行處理,然後返回到doInBackground中進行下一步處理。
/**
 * @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(ArrayList content){
		return content != null && content.size() > 0;
	}
}
8. UI線程中具體調用方法如下:
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 上面:如圖所示:

[l逗'€?燐-畨?皋r?棣薢珊趩窡源碼下載:http://download.csdn.net/detail/fu222cs98/7377683

歡迎轉載,轉載注明出處,謝謝
Mr.傅:Stay


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved