Android之Http網絡編程(四)

前面幾篇博文簡單的介紹了一些常見的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;}@Overrideprotected void onPreExecute() {// TODO Auto-generated method stubsuper.onPreExecute();}@Overrideprotected 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;}}@Overrideprotected void onPostExecute(Object result) {if (requset.callback != null) {if (result instanceof Exception) {requset.callback.onFailure((Exception) result);} else {requset.callback.onSuccess(result);}}}@Overrideprotected void onProgressUpdate(integer... values) {// TODO Auto-generated method stubsuper.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;@Overrideprotected 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() {@Overridepublic void onClick(View v) {try {request.setCallBack(new HttpCallback() {@Overridepublic void onSuccess(Object result) {tv.setText((String) result);}@Overridepublic 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" ><Buttonandroid:id="@+id/btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="請求" /><ScrollViewandroid:id="@+id/sv"android:layout_width="match_parent"android:layout_height="wrap_content" ><TextViewandroid: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

轉載于:https://www.cnblogs.com/scetopcsa/p/4021196.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/273551.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/273551.shtml
英文地址,請注明出處:http://en.pswp.cn/news/273551.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《Java 高并發》02 多線程的特性

多線程的三大特性&#xff1a;原子性、可見性和有序性。 原子性 原子性是指一個操作或者多個操作&#xff0c;一旦開始就不會被其他線程干擾&#xff0c;即使是在多個線程一起執行的情況下也不會被干擾。或者不執行。 原子性主要是為了保證數據一致&#xff0c;線程安全問題…

U3D-FSM有限狀態機的簡單設計

http://coder.beitown.com/archives/592 在之前的文章里介紹了一個基礎U3D狀態機框架&#xff08;Unity3D游戲開發之狀態流框架&#xff09;即大Switch的枚舉狀態控制。這種方法雖然容易理解&#xff0c;編程方法也相對簡單&#xff0c;但是弊端是當狀態變得復雜之后&#xff0…

《Java 高并發》04 線程的基本操作

新建線程 新建線程很簡單。只要使用new 關鍵字創建一個線程對象&#xff0c;并且調用 start 方法啟動線程。 Thread t new Thread(); t.start();注意&#xff1a;run 方法不是用來啟動線程。如果調用 run 方法它只會作為普通方法來執行&#xff0c;而不會開啟線程執行。 終止…

Dispatch 方法簡介

后臺執行 dispatch_async(dispatch_get_global_queue(0, 0), ^{ //后臺程執行 something; }); 主線程執行 dispatch_async(dispatch_get_main_queue(), ^{// 主線程執行something; }); 一次性執行 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // 主…

linux雜七雜八整理

64系統里執行32位程序&#xff1a; 1、在64系統里執行32位程序如果出現/lib/ld-linux.so.2: bad ELF interpreter: No such file or directory&#xff0c;安裝下glic即可sudo yum install glibc.i6862、error while loading shared libraries: libz.so.1: cannot …

《Java 高并發》05 線程的基本操作

volatile 與 Java 內存模型 Java 內存模型都是圍繞著原子性、有序性和可見性展開的。為了在適當的場合&#xff0c;確保線程間的原子性、有序性和可見性。Java 使用了一些特許的操作或者關鍵字來申明、告訴虛擬機&#xff0c;在這個地方&#xff0c;要尤其注意&#xff0c;不能…

mybatis 2 -常用數據操作

1、寫入數據并獲取自增ID XML配置&#xff1a; <!-- 寫入數據獲取自增ID --><insert id"insertLog" parameterType"com.mamaguwen.entity.sys_loginlog" useGeneratedKeys"true" keyProperty"logid">insert into sys_…

Spring常用的的注解對應xml配置詳解

Component(value"")注解&#xff1a;組件 標記在類上&#xff0c;也可以放在接口上注解作用&#xff1a;把AccountDao實現類對象交由Spring IOC容器管理 相當于XML配置文件中的Bean標簽 <bean id"userAnnonMapper" class"com.spring.mapper.User…

安卓模擬器bluestacks mac地址修改教程

http://szmars2008.blog.163.com/blog/static/118893702201373181349348/ 轉載于:https://www.cnblogs.com/prayer521/p/4069037.html

Docker 搭建 ELK 日志系統,并通過 Kibana 查看日志

Docker 搭建 ELK 日志系統,并通過 Kibana 查看日志 docker-compose.yml version: 3 services:elasticsearch:image: elasticsearch:7.7.0 #鏡像container_name: elasticsearch #定義容器名稱restart: always #開機啟動&#xff0c;失敗也會一直重啟environment:- "cl…

蟠桃記

Problem Description 喜歡西游記的同學肯定都知道悟空偷吃蟠桃的故事&#xff0c;你們一定都覺得這猴子太鬧騰了&#xff0c;其實你們是有所不知&#xff1a;悟空是在研究一個數學問題&#xff01; 什么問題&#xff1f;他研究的問題是蟠桃一共有多少個&#xff01; 不過&#…

Spring 定時任務動態管理

管理 Spring 中定時任務 pom.xml <properties><hutool.version>5.6.6</hutool.version><lombok.version>1.18.20</lombok.version><spring-boot.web.version>2.2.10.RELEASE</spring-boot.web.version> </properties><de…

高效率Oracle SQL語句

1、Where子句中的連接順序&#xff1a; ORACLE采用自下而上的順序解析WHERE子句。 根據這個原理&#xff0c;表之間的連接必須寫在其他WHERE條件之前&#xff0c; 那些可以過濾掉最大數量記錄的條件必須寫在WHERE子句的末尾。 舉例&#xff1a; (低效) select ... from table1…

RabbitMQ Management:Management API returned status code 500

錯誤顯示&#xff1a; 解決方案&#xff1a; 因為是使用docker 容器安裝的&#xff0c;所有需要進入容器 docker exec -it rabbitmq /bin/bash進入目錄 cd /etc/rabbitmq/conf.d/執行命令 echo management_agent.disable_metrics_collector false > management_agent.dis…

Android JNI和NDK學習(5)--JNI分析API

Java類型和本地類型對應 在如下情況下&#xff0c;需要在本地方法中應用java對象的引用&#xff0c;就會用到類型之間的轉換&#xff1a; java方法里面將參數傳入本地方法&#xff1b;在本地方法里面創建java對象&#xff1b;在本地方法里面return結果給java程序。Java基本類型…

RabbitMq 消費失敗,重試機制

方案一&#xff1a; 本地消息表 定時任務 本地消息表&#xff1a;主要用于存儲 業務數據、交換機、隊列、路由、次數 定時任務&#xff1a;定時掃描本地消息表&#xff0c;重新給業務隊列投遞消息。 具體思路&#xff1a;業務隊列消費失敗時&#xff0c;把 業務數據、交換機、…

Android常用的工具類

主要介紹總結的Android開發中常用的工具類&#xff0c;大部分同樣適用于Java。目前包括HttpUtils、DownloadManagerPro、ShellUtils、PackageUtils、 PreferencesUtils、JSONUtils、FileUtils、ResourceUtils、StringUtils、 ParcelUtils、RandomUtils、ArrayUtils、ImageUtils…

0. Spring 基礎

BeanDefinition BeanDefinition 表示 Bean 定義&#xff1a; Spring根據BeanDefinition來創建Bean對象&#xff1b;BeanDefinition有很多的屬性用來描述Bean&#xff1b;BeanDefiniton是Spring中非常核心的概念。BeanDefiniton中重要的屬性&#xff1a; a. beanClass&#xf…

1. Spring 源碼:Spring 解析XML 配置文件,獲得 Bena 的定義信息

通過 Debug 運行 XmlBeanDefinitionReaderTests 類的 withFreshInputStream() 的方法&#xff0c;調試 Spring 解析 XML 配置文件&#xff0c;獲得 Bean 的定義。 大體流程可根據序號查看&#xff0c;xml 配置文件隨便看一眼&#xff0c;不用過多在意。 <?xml version&qu…

c++ 讀取文件 最后一行讀取了兩次

用ifstream的eof()&#xff0c;竟然讀到文件最后了&#xff0c;判斷eof還為false。網上查找資料后&#xff0c;終于解決這個問題。 參照文件&#xff1a;http://tuhao.blogbus.com/logs/21306687.html 在使用C/C讀文件的時候&#xff0c;一定都使用過eof&#xff08;&#xff0…