Android開發之網路請求通訊專題(一):基於HttpURLConnection的請求通訊

來源:互聯網
上載者:User

標籤:android網路訪問   http訪問   網路通訊   httpurlconnection   android下http通訊   

在Android開發中,網路請求必然是必不可少。一般而言,都是基於http的網路請求。有時候也會有SOCKET請求,這個後續的專題再講。今天,我們就先講講常用的Http請求。

http求情自然是遵循http協議的,相關內容請轉接:Java學習筆記之Http協議詳解

好了,開始今天的正題。


一、基礎HTTPURL請求方式我們先來看一個最簡單的例子,通過get方法請求拿到返回值1、用get方式請求
URL url = new URL("http://192.168.31.144:10010/MINATest/servlet/DataTestServlet?username=victor&password=strikefreedom");HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(TIME);conn.setReadTimeout(TIME);int responseCode = conn.getResponseCode();if (responseCode == 200) {input = conn.getInputStream();if (input != null) {//拿到流後處理}}

2、用post方式請求
String data = "username=justice&password=infiniteJustice";URL url = new URL("http://192.168.31.144:10010/MINATest/servlet/DataTestServlet");conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(TIME);conn.setReadTimeout(TIME);conn.setDoInput(true);// 允許輸入conn.setDoOutput(true);// 允許輸出conn.setUseCaches(false);// 不使用Cacheconn.setRequestProperty("Charset", ENCODING);conn.setRequestProperty("Content-Length",String.valueOf(data.length()));conn.setRequestProperty("Content-Type", "text/*;charset=utf-8");conn.setRequestMethod("POST");DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());outStream.write(data.getBytes());outStream.flush();outStream.close();if (conn == null) {return;}int responseCode = conn.getResponseCode();if (responseCode == 200) {input = conn.getInputStream();if (input != null) {}}

我們可以看到用post方式請求和用get方式傳入參數有點不同。
二、http訪問類的封裝
1、封裝邏輯我們知道,在android開發中,網路訪問的東西都是不能再UI線程中執行的,只能在子線程裡面執行,得到結果後通知主線程重新整理UI。這個訊息通知機制博主就不在詳細秒速,有興趣的朋友請轉接:Android非同步處理系列文章索引在正常的開發中,我們不會每次請求,都像上面那樣的簡單去寫,我們需要做一定的封裝處理,來使代碼更加的簡潔,架構更加的清晰。那麼我們需要這麼四個東西
1、http訪問管理者2、訊息通訊管理者handler3、http訪問結果監聽器4、http訪問結果事件處理回調介面。整個邏輯關係為:http訪問管理者採用get或者post請求方式請求,當產生結果後監聽器告訴訊息通訊管理者應該發送什麼訊息給UI線程,UI線程更具訊息通訊管理者發送過來的訊息,調用對應的事件處理回調介面。
那麼我們來一一對應看這四個類該如何編寫。
2、http訪問管理者http訪問管理者,如其名,裡面需要封裝兩種請求。正常情況下,在構造出http訪問管理者的時候,需要傳入一個通訊協定的類進入,裡面應該包含請求地址以及請求資訊,這裡博主為了方便省事,沒有出入,直接寫死了。有興趣的同學可以根據自身實際需求更改。看代碼:
package com.example.nettest;import java.io.ByteArrayOutputStream;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.net.HttpURLConnection;import java.net.SocketException;import java.net.SocketTimeoutException;import java.net.URL;import java.net.URLEncoder;import java.util.HashMap;import java.util.Map;import android.content.Context;import android.text.TextUtils;import android.util.Log;/** * @ClassName: FreedomHttpUrlUtils * @author victor_freedom ([email protected]) * @createddate 2015-1-22 下午1:43:58 * @Description: http要求管理者 */public class FreedomHttpUrlUtils implements Runnable {private Context context;/** http訪問結果監聽器 */private FreedomHttpListener listener;/** 當前訪問線程 */private Thread currentRequest = null;/** 訪問連結 */HttpURLConnection conn = null;/** 拿到的流 */InputStream input = null;private static final String ENCODING = "UTF-8";public static final int GET_MOTHOD = 1;private static final int TIME = 40 * 1000;public static final int POST_MOTHOD = 2;/** * 1: get請求 2: post請求 */private int requestStatus = 1;/** * <p> * Title: * </p> * <p> * Description:構造方法,其實在這裡可以傳入一個傳輸協議包,博主是測試代碼,所以請求中直接寫死了。 * </p> *  * @param mContext * @param listener *            監聽器 * @param mRequeststatus *            請求方式 */public FreedomHttpUrlUtils(Context mContext, FreedomHttpListener listener,int mRequeststatus) {this.context = mContext;this.requestStatus = mRequeststatus;this.listener = listener;}/** * @Title: postRequest * @Description:Post請求觸發 * @throws */public void postRequest() {requestStatus = 2;currentRequest = new Thread(this);currentRequest.start();}/** * @Title: getRequeest * @Description:GET請求觸發 * @throws */public void getRequeest() {requestStatus = 1;currentRequest = new Thread(this);currentRequest.start();}/** * 對請求的字串進行編碼 *  * @return * @throws UnsupportedEncodingException */public static String requestEncodeStr(String requestStr)throws UnsupportedEncodingException {return URLEncoder.encode(requestStr, ENCODING);}/** * @Title: sendGetRequest * @Description: 發送get請求 * @throws */private void sendGetRequest() {try {URL url = new URL("http://192.168.31.144:10010/MINATest/servlet/DataTestServlet?username=victor&password=strikefreedom");HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(TIME);conn.setReadTimeout(TIME);int responseCode = conn.getResponseCode();if (responseCode == 200) {input = conn.getInputStream();if (input != null) {listener.action(FreedomHttpListener.EVENT_GET_DATA_SUCCESS,readStream(input));}} else {listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);}} catch (SocketException e) {e.printStackTrace();listener.action(FreedomHttpListener.EVENT_CLOSE_SOCKET, null);} catch (SocketTimeoutException e) {e.printStackTrace();listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);} catch (IOException e) {e.printStackTrace();listener.action(FreedomHttpListener.EVENT_GET_DATA_EEEOR, null);} catch (Exception e) {e.printStackTrace();listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);}}/** * @Title: sendPostRequest * @Description: 發送post請求 * @throws */private void sendPostRequest() {try {String data = "username=justice&password=infiniteJustice";URL url = new URL("http://192.168.31.144:10010/MINATest/servlet/DataTestServlet");conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(TIME);conn.setReadTimeout(TIME);conn.setDoInput(true);// 允許輸入conn.setDoOutput(true);// 允許輸出conn.setUseCaches(false);// 不使用Cacheconn.setRequestProperty("Charset", ENCODING);conn.setRequestProperty("Content-Length",String.valueOf(data.length()));conn.setRequestProperty("Content-Type", "text/*;charset=utf-8");conn.setRequestMethod("POST");DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());outStream.write(data.getBytes());outStream.flush();outStream.close();if (conn == null) {return;}int responseCode = conn.getResponseCode();if (responseCode == 200) {input = conn.getInputStream();if (input != null) {listener.action(FreedomHttpListener.EVENT_GET_DATA_SUCCESS,readStream(input));}} else if (responseCode == 404) {input = conn.getErrorStream();if (input != null) {listener.action(FreedomHttpListener.EVENT_GET_DATA_SUCCESS,readStream(input));} else {listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR,null);}} else {listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);}} catch (SocketException e) {e.printStackTrace();listener.action(FreedomHttpListener.EVENT_CLOSE_SOCKET, null);} catch (SocketTimeoutException e) {e.printStackTrace();listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);} catch (IOException e) {e.printStackTrace();listener.action(FreedomHttpListener.EVENT_GET_DATA_EEEOR, null);} catch (Exception e) {e.printStackTrace();listener.action(FreedomHttpListener.EVENT_NETWORD_EEEOR, null);}}/** * @Title: isRunning * @Description: 判斷是否正在訪問 * @return * @throws */public boolean isRunning() {if (currentRequest != null && currentRequest.isAlive()) {return true;}return false;}/** * 讀取資料 *  * @param inStream *            輸入資料流 * @return * @throws Exception */private Object readStream(InputStream inStream) throws Exception {String result;ByteArrayOutputStream outStream = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = -1;while ((len = inStream.read(buffer)) != -1) {outStream.write(buffer, 0, len);}result = new String(outStream.toByteArray(), ENCODING);outStream.close();inStream.close();return result;}/** * 取消當前HTTP串連處理 */public void cancelHttpRequest() {if (currentRequest != null && currentRequest.isAlive()) {if (input != null) {try {input.close();} catch (Exception e) {e.printStackTrace();}}input = null;if (conn != null) {try {conn.disconnect();} catch (Exception e) {e.printStackTrace();}}conn = null;currentRequest = null;System.gc();}}/** * 發送請求 */public void run() {// 判斷是否有網路boolean netType = NetUtils.checkNetWork(context);if (netType) {if (requestStatus == 1) {sendGetRequest();} else if (requestStatus == 2) {sendPostRequest();}} else {listener.action(FreedomHttpListener.EVENT_NOT_NETWORD, null);}}}

我們可以看到,當訪問有結果以後,會出發監聽器的action方法,那麼我們再來看看監聽器的定義3、http訪問結果監聽器
package com.example.nettest;/** * @ClassName: FreedomHttpListener * @author victor_freedom ([email protected]) * @createddate 2015-1-24 下午4:28:31 * @Description: 監聽器 */public interface FreedomHttpListener {public static final int EVENT_BASE = 0x100;/** * 沒有網路的資訊提示 * */public static final int EVENT_NOT_NETWORD = EVENT_BASE + 1;/** * 網路異常的資訊提示 * */public static final int EVENT_NETWORD_EEEOR = EVENT_BASE + 2;/** * 擷取網路資料失敗 * */public static final int EVENT_GET_DATA_EEEOR = EVENT_BASE + 3;/** * 擷取網路資料成功 * */public static final int EVENT_GET_DATA_SUCCESS = EVENT_BASE + 4;/** * 擷取網路資料成功 * */public static final int EVENT_CLOSE_SOCKET = EVENT_BASE + 5;public void action(int actionCode, Object object);}

我們可以看到,在觸發action動作的時候,我們會傳入一個code和一個對象,這個code表示當前訪問是否成功,而對象就是要傳輸的訪問結果。我們再看看訊息處理器是如何工作的
4、訊息處理器
/** * @ClassName: BaseHandler * @author victor_freedom ([email protected]) * @createddate 2015-1-24 下午4:32:05 * @Description: 訊息處理器 */class BaseHandler extends Handler {private Context context;/** 事件回調介面處理 */private FreedomDataCallBack callBack;public BaseHandler(Context context, FreedomDataCallBack callBack) {this.context = context;this.callBack = callBack;}public void handleMessage(Message msg) {// 根據不同的結果觸發不同的動作if (msg.what == FreedomHttpListener.EVENT_GET_DATA_SUCCESS) {if (msg.obj == null) {callBack.onFailed();} else {// 幕後處理資料callBack.processData(msg.obj, true);}} else if (msg.what == FreedomHttpListener.EVENT_NOT_NETWORD) {callBack.onFailed();// CommonUtil.showInfoDialog(context,// getString(R.string.net_error));} else if (msg.what == FreedomHttpListener.EVENT_NETWORD_EEEOR) {callBack.onFailed();} else if (msg.what == FreedomHttpListener.EVENT_GET_DATA_EEEOR) {callBack.onFailed();} else if (msg.what == FreedomHttpListener.EVENT_CLOSE_SOCKET) {}callBack.onFinish();}}

我們可以看到,在訊息處理器中傳入了一個回調介面類,在不同的返回結果中,觸發不同的回調動作。
5、回調介面
package com.example.nettest;/** * @ClassName: FreedomDataCallBack * @author victor_freedom ([email protected]) * @createddate 2015-1-24 下午4:33:38 * @Description: 回調介面,處理返回資料 * @param <T> */public interface FreedomDataCallBack<T> {public abstract void onStart();public abstract void processData(T paramObject, boolean paramBoolean);public abstract void onFinish();public abstract void onFailed();}

因為我們不知道返回的結果是什麼類型的,這裡採用泛型來處理

三、http封裝後的使用1、從伺服器拿資料的方法所有的東西我們都已經封裝好了之後,該怎麼使用呢?我們來嘗試寫一個方法吧,從伺服器擷取資料並返回。我們先寫一個getDataFromserver的方法在基類中
/** * @Title: getDataFromServer * @Description: 從伺服器拿資料 * @param requestType *            請求方式 * @param callBack *            回調介面 * @throws */protected void getDataFromServer(int requestType,FreedomDataCallBack callBack) {final BaseHandler handler = new BaseHandler(this, callBack);freedomHttpUrlUtils = new FreedomHttpUrlUtils(mContext,new FreedomHttpListener() {@Overridepublic void action(int actionCode, Object object) {Message msg = new Message();switch (actionCode) {case FreedomHttpListener.EVENT_NOT_NETWORD:msg.what = FreedomHttpListener.EVENT_NOT_NETWORD;break;case FreedomHttpListener.EVENT_NETWORD_EEEOR:msg.what = FreedomHttpListener.EVENT_NETWORD_EEEOR;break;case FreedomHttpListener.EVENT_CLOSE_SOCKET:msg.what = FreedomHttpListener.EVENT_CLOSE_SOCKET;break;case FreedomHttpListener.EVENT_GET_DATA_EEEOR:msg.what = FreedomHttpListener.EVENT_GET_DATA_EEEOR;msg.obj = null;break;case FreedomHttpListener.EVENT_GET_DATA_SUCCESS:msg.obj = object;msg.what = FreedomHttpListener.EVENT_GET_DATA_SUCCESS;break;default:break;}handler.sendMessage(msg);}}, requestType);callBack.onStart();// 選擇不同的要求方法if (requestType == FreedomHttpUrlUtils.GET_MOTHOD) {freedomHttpUrlUtils.getRequeest();} else if (requestType == FreedomHttpUrlUtils.POST_MOTHOD) {freedomHttpUrlUtils.postRequest();}}

2、方法的使用我們在主Activity中啟用一下這個方法。為了方便,博主這裡是提交了什麼參數就返回什麼參數。這裡提交的參數統一為username和password形式。請求詳細參數請看FreedomHttpUrlUtils中。我們先看服務端的處理方式:
@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String parameter = request.getParameter("username");String parameter2 = request.getParameter("password");System.out.println(parameter + parameter2);response.setContentType("text/*;charset=utf-8");response.getWriter().write(parameter + "-" + parameter2);}@Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// doGet(request, response);System.out.println("post");ServletInputStream inputStream = request.getInputStream();ByteOutputStream b = new ByteOutputStream();int len = -1;byte[] buf = new byte[1024];while ((len = inputStream.read(buf)) != -1) {b.write(buf, 0, buf.length);}String s = b.toString();String[] split = s.split("&");System.out.println(split[0] + split[1]);response.setContentType("text/*;charset=utf-8");response.getWriter().write(split[0].substring(split[0].lastIndexOf("=") + 1) + "-"+ split[1].substring(split[1].lastIndexOf("=") + 1));}

我們在看在activity中的調用:
/*** @ClassName: MainActivity* @author victor_freedom ([email protected])* @createddate 2015-1-24 下午4:40:59* @Description: TODO */public class MainActivity extends BaseActivity {private TextView get;private TextView post;@Overrideprotected void findViewById() {get = (TextView) findViewById(R.id.hello);post = (TextView) findViewById(R.id.post);}@Overrideprotected void loadViewLayout() {setContentView(R.layout.activity_main);}@Overrideprotected void processLogic() {}@Overrideprotected void setListener() {}@Overrideprotected void init() {getDataFromServer(1, new FreedomDataCallBack<String>() {@Overridepublic void onStart() {}@Overridepublic void processData(String paramObject, boolean paramBoolean) {get.setText(paramObject);}@Overridepublic void onFinish() {}@Overridepublic void onFailed() {}});getDataFromServer(2, new FreedomDataCallBack<String>() {@Overridepublic void onStart() {}@Overridepublic void processData(String paramObject, boolean paramBoolean) {post.setText(paramObject);}@Overridepublic void onFinish() {}@Overridepublic void onFailed() {}});}

我們這裡分別採用了兩種方法訪問,傳入參數也是不同的,我們看訪問結果,兩個textView均顯示了訪問返回的值。



好了,第一篇關於http訪問的文章已經講解完畢,希望能夠協助到看到此文的人。下一篇我們講解如何使用httpclient類來實現http網路請求,並實現檔案的上傳和下載功能。

Android開發之網路請求通訊專題(一):基於HttpURLConnection的請求通訊

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.