標籤:android style blog http color io os ar 使用
前面幾篇博文簡單的介紹了一些常見的Http的操作,這些操作幾乎都是在新開的線程中進行的網路請求,並在日誌中列印出擷取到的網路資料。那麼,問題來了!(呃~感覺下一句是藍翔有木有?)如何在把擷取到的網路資料顯示在UI介面上呢?如果按照前幾篇博文的例子,並在主線程中直接對子線程擷取的網路資料直接進行操作就會發現一個問題,那就是在主線程中根本就擷取不到子線程得到的從伺服器返回的資料。因為,網路操作屬於耗時操作,為了不阻塞主線程而放在子線程中,當主線程中的代碼執行完後子線程未必就擷取到伺服器返回的資料了。所以,為瞭解決這樣的問題我們通常在Http的操作中加上非同步訊息機制,並且為了簡化操作對其進行簡單的封裝,加上回調機制。
這篇博文就以HttpClient訪問百度首頁為例子,對之前博文中的Http操作進一步的完善。
首先,先回憶一下使用HttpClient的最簡單的步驟或者說是過程:
(這裡的strurl為"http://www.baidu.com",str為從伺服器返回的資料。)
HttpClient client = new DefaultHttpClient();HttpGet request = new HttpGet(strurl);HttpResponse response= client.execute(request);if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {String str = EntityUtils.toString(response.getEntity());}
下面將基於上面的這些操作來實現簡易封裝:
首先加入回調機制:
(如果對回調還不太熟悉,請參考博文《java回調機制解析》)
public interface HttpCallback { void onSuccess(Object result); void onFailure(Exception result);}
接下來,實現一個Request類:
這個類一共有三個屬性:
method是在該類中用enum類型限定的RequestMethod類型的對象,用於佈建要求方式。
url就是網路請求的路徑。
callback為回調介面對象,用於在網路請求中擷取到資料後將資料傳遞至調用處。
public class Request { public RequestMethod method; public String url; public HttpCallback callback; public Request(String url, RequestMethod method) { this.method = method; this.url = url; } public Request(String url) { this.method = RequestMethod.GET; this.url = url; } public enum RequestMethod { GET, POST, DELETE, PUT } public void setCallBack(HttpCallback callback) { this.callback = callback; } public void execute() { RequstTask task = new RequstTask(this); task.execute(); }}
從上面的代碼可以看出,該類的兩個建構函式,都需要傳入URL,其中一個建構函式可以佈建要求方式,另一個設定預設請求方式GET。
在該類中有一個execute()方法,在這個方法中RequestTask類繼承於AsyncTask,它的作用就是在RequestTask中進行網路請求。
RequestTask代碼如下:
public class RequstTask extends AsyncTask<Void, integer, Object> { private Request requset; public RequstTask(Request requset) { this.requset = requset; } @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); } @Override protected Object doInBackground(Void... params) { try { HttpResponse response = HttpClientUtils.execute(requset); if (requset.callback != null) { //如果進一步抽象化回調介面,使其子抽象類別能分別處理多種格式的資料(如:JSON、XML、String、File),可以更方便 //這裡直接使用返回String類型的資料 if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){ return EntityUtils.toString(response.getEntity()); } return "請求失敗"; } else { return null; } } catch (Exception e) { return e; } } @Override protected void onPostExecute(Object result) { if (requset.callback != null) { if (result instanceof Exception) { requset.callback.onFailure((Exception) result); } else { requset.callback.onSuccess(result); } } } @Override protected void onProgressUpdate(integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); }}
這個類的建構函式需要傳遞一個Request對象,會根據這個Request對象的method屬性確定請求方式、url屬性確定請求路徑,根據callback屬性的有無來判斷是否是否將擷取到的網路資料傳遞至調用介面處。
在doInBackground()中如果Request對象的callback屬性為null則返回null:
當Request對象的callback屬性不為null,則先取出伺服器返回的狀態代碼(這裡的response為伺服器返回的資訊),如果等於200(也就是HttpStatus.SC_OK)那麼就說明響應成功了。再調用getEntity()方法擷取到一個HttpEntity執行個體,然後再用EntityUtils.toString()這個靜態方法將HttpEntity轉換成字串並return。返回後的資料將傳入onPostExecute()方法中作為參數。
if (requset.callback != null) { //如果進一步抽象化回調介面,使其子抽象類別能分別處理多種格式的資料(如:JSON、XML、String、File),可以更方便 //這裡直接使用返回String類型的資料 if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){ return EntityUtils.toString(response.getEntity()); } return "請求失敗"; } else { return null; }
在onPostExecute()中Request對象的callback屬性為null根本就沒返回。反之,doInBackground()的結果result將會傳遞至回調介面的調用處:
if (requset.callback != null) { if (result instanceof Exception) { requset.callback.onFailure((Exception) result); } else { requset.callback.onSuccess(result); } }
在doInBackground()中有一句代碼:
HttpResponse response = HttpClientUtils.execute(requset);
這裡的HttpClientUtils其實就是一個簡單的封裝,其代碼如下:
public class HttpClientUtils { public static HttpResponse execute(Request requst) throws Exception { switch (requst.method) { case GET: return get(requst); } return null; } private static HttpResponse get(Request requst) throws ClientProtocolException, IOException { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(requst.url); HttpResponse response = client.execute(get); return response; }}
從代碼中可以看出,execute()和get()方法都是static類型並且傳回型別都是HttpResponse。在execute()方法中根據傳入的Request對象的method屬性結合switch語句執行相對應的網路請求方式,並返回從伺服器獲得HttpResponse類型的資訊。這個資訊在RequstTask類中被直接賦值使用。
大體的過程就是這樣了。
最後的最後,在Activity中的使用:
public class MainActivity extends Activity { private Button btn; private TextView tv; private Request request; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btn = (Button) findViewById(R.id.btn); tv = (TextView) findViewById(R.id.tv); request = new Request("http://www.baidu.com", RequestMethod.GET); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { request.setCallBack(new HttpCallback() { @Override public void onSuccess(Object result) { tv.setText((String) result); } @Override public void onFailure(Exception result) { tv.setText("請求失敗"); } }); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } request.execute(); } }); }}
Activity的布局檔案如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="請求" /> <ScrollView android:id="@+id/sv" android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/tv" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </ScrollView></LinearLayout>
View Code
運行程式,效果如下:
Demo下載:http://download.csdn.net/detail/af74776/8066779
Android之Http網路編程(四)