前面几篇博文简单的介绍了一些常见的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>

运行程序,效果如下:

Demo下载:http://download.csdn.net/detail/af74776/8066779

Android之Http网络编程(四)的更多相关文章

  1. Android之Http网络编程(三)

    在前面两篇博客<Android之Http网络编程(一)>.<Android之Http网络编程(二)>中,简单的介绍了对网页的请求和客户端与服务端的简单的参数交互.那么,这一篇博 ...

  2. Android之Http网络编程(一)

    Android应用作为一个客户端程序绝大部分都是需要进行网络请求和访问的,而http通信是一种比较常见并常用的通信方式. 在Android中http网络编程中有两种实现方式,一种是使用HttpURLC ...

  3. Java高并发网络编程(四)Netty

    在网络应用开发的过程中,直接使用JDK提供的NIO的API,比较繁琐,而且想要进行性能提升,还需要结合多线程技术. 由于网络编程本身的复杂性,以及JDK API开发的使用难度较高,所以在开源社区中,涌 ...

  4. Android应用开发-网络编程(一)(重制版)

    网络图片查看器 1. 确定图片的网址 2. 发送http请求 URL url = new URL(address); // 获取客户端和服务器的连接对象,此时还没有建立连接 HttpURLConnec ...

  5. Linux 网络编程四(socket多线程升级版)

    //网络编程--客户端 #include <stdio.h> #include <stdlib.h> #include <string.h> #include &l ...

  6. Linux网络编程(四)

    在linux网络编程[1-3]中,我们编写的网络程序仅仅是为了了解网络编程的基本步骤,实际应用当中的网络程序并不会用那样的.首先,如果服务器需要处理高并发访问,通常不会使用linux网络编程(三)中那 ...

  7. Android应用开发-网络编程(一)

    网络图片查看器 1. 确定图片的网址 2. 发送http请求 URL url = new URL(address); // 获取客户端和服务器的连接对象,此时还没有建立连接 HttpURLConnec ...

  8. Android中的网络编程

    谷歌在Android6.0之后就废弃了使用HttpClinet进行网络连接.所以,这里需要重点学习的是通过HttpUrlConnect进行网络连接. String path="这里是你想要的 ...

  9. Android之Http网络编程(二)

    上一篇文章简单的介绍了Android中http的两种通信方式,并且分别用获取百度网页做了实例.但是在实际应用中,更多的是客户端通过请求的参数来实现在服务端的具体操作,并最终返回数据给客户端.因为我们不 ...

随机推荐

  1. 洛谷 P1373 小a和uim之大逃离

    2016-05-30 12:31:59 题目链接: P1373 小a和uim之大逃离 题目大意: 一个N*M的带权矩阵,以任意起点开始向右或者向下走,使得奇数步所得权值和与偶数步所得权值和关于K的余数 ...

  2. C 头文件阅读理解

    __BEGIN_DECLS ..... ..... __END_DECLS 很多时候,为了使 C 代码和 C++ 代码保持互相兼容的过程调用接口,需要在 C++ 代码里加上 extern " ...

  3. Spark生态

  4. nyoj 218 Dinner

    Dinner 时间限制:100 ms  |  内存限制:65535 KB 难度:1   描述 Little A is one member of ACM team. He had just won t ...

  5. altium designer 里如何设置PCB默认字符默认大小(PCB丝印)

    注意:此操作只对新导入的元件生效.      

  6. Jquery ajax 得到返回值

    Jquery ajax 得到返回值 1.ajax默认是异步调用的,所以得到的返回值是空值,要得到值必须改成同步:async: false,//同步. 2.必须定义一个全局变量 var result = ...

  7. paip.云计算以及分布式计算的区别

    paip.云计算以及分布式计算的区别 云计算的特点 1 网格计算 2 分布式计算 2 云计算以及网格计算以及分布式计算的区别 2 作者Attilax  艾龙,  EMAIL:1466519819@qq ...

  8. mysql事物

    一. 什么是事务 事务就是一段sql 语句的批处理,但是这个批处理是一个atom(原子) ,不可分割,要么都执行,要么回滚(rollback)都不执行. 二.为什么出现这种技术 为什么要使用事务这个技 ...

  9. hdu 2844 Coins (多重背包)

    题意是给你几个数,再给你这几个数的可以用的个数,然后随机找几个数来累加, 让我算可以累加得到的数的种数! 解题思路:先将背包初始化为-1,再用多重背包计算,最后检索,若bb[i]==i,则说明i这个数 ...

  10. 用csc命令行手动编译cs文件

    一般初学c#时,用记事本写代码,然后用命令行执行csc命令行可以编译cs文件.方法有两种 1:配置环境,一劳永逸 一般来说在C:\Windows\Microsoft.NET\Framework\v4. ...