前面几篇博文简单的介绍了一些常见的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. ubuntu 13.04下sublime text 3使用中文输入法

    主要思路参考 http://blog.yanwen.org/archives/1955.html libsublime-imfix.so 这个库自己编译和从他这下载的 md5一样.可以不用编译了.直接 ...

  2. windows 2003 插金税盘 可以识别, 但是会蓝屏重启

  3. Android实例-录音与回放(播放MP3)(XE8+小米2)

    结果: 1.增加ActionList中的Action时,需要跳到Master界面,不能在Android4Phonel界面下. 2.如果不打开权限的话,会提示“该设备不支持停止录音操作”(Record ...

  4. 运用集合来做一个DVD管理器(全代码)

    package DVD;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Array ...

  5. Dom深入浅出

    Dom1级提供了一个Node接口,该接口将由Dom中所有节点类型(包括元素节点.文本节点.属性节点等12种)实现,而js是作为Node类型来实现的,js中的所有节点类型的继承自Node类型, 所以它们 ...

  6. NGUI学习笔记(二):基础笔记

    精灵(Sprite).图集(Atlas)和贴图(Texture)的区别 图集:由多张小图拼合而成的一张大图,其好处是降低DrawCall的次数.减少载入内存的次数和方便管理同一类型的小图.一般图集都会 ...

  7. SqlLite ---.net连接数据库

    初识SqlLite ---.net连接数据库   SqlLite以小巧和嵌入式闻名,以前只是听说,现在终于忍不住要尝试下. 先下载ADO.NET2.0 Provider for SQLite,下载完后 ...

  8. jsp应用bootstrap表格应用实例

    一.初始化表格 <div style="margin-top: 80px;margin-left:45px;margin-right:30px;overflow-x: scroll&q ...

  9. SQLite使用教程4 创建数据库

    http://www.runoob.com/sqlite/sqlite-create-database.html SQLite 创建数据库 SQLite 的 sqlite3 命令被用来创建新的 SQL ...

  10. Libgdx Box2D真实---这缓释微丸(三:规则经常使用body和精灵联合)

    介绍规则body怎样和图片结合.上一篇文章我介绍了box2D的基本知识,假设你用心的话.你会搜索网上相关简单demo吧.那些我就不写了.那么假设我用图片表示我的那个body.而不是简单线条.那该怎么办 ...