网上介绍Android上http通信的文章很多,不过大部分只给出了实现代码的片段,一些注意事项和如何设计一个合理的类用来处理所有的http请求以及返回结果,一般都不会提及。因此,自己对此做了些总结,给出了我的一个解决方案。
首先,需要明确一下http通信流程,Android目前提供两种http通信方式,HttpURLConnection和HttpClient,HttpURLConnection多用于发送或接收流式数据,因此比较适合上传/下载文件,HttpClient相对来讲更大更全能,但是速度相对也要慢一点。在此只介绍HttpClient的通信流程:
1.创建HttpClient对象,改对象可以用来多次发送不同的http请求
2.创建HttpPost或HttpGet对象,设置参数,每发送一次http请求,都需要这样一个对象
3.利用HttpClient的execute方法发送请求并等待结果,该方法会一直阻塞当前线程,直到返回结果或抛出异常。
4.针对结果和异常做相应处理
根据上述流程,发现在设计类的时候,有几点需要考虑到:
1.HttpClient对象可以重复使用,因此可以作为类的静态变量
2.HttpPost/HttpGet对象一般无法重复使用(如果你每次请求的参数都差不多,也可以重复使用),因此可以创建一个方法用来初始化,同时设置一些需要上传到服务器的资源
3.目前Android不再支持在UI线程中发起Http请求,实际上也不该这么做,因为这样会阻塞UI线程。因此还需要一个子线程,用来发起Http请求,即执行execute方法
4.不同的请求对应不同的返回结果,对于如何处理返回结果(一般来说都是解析json&更新UI),需要有一定的自由度。
5.最简单的方法是,每次需要发送http请求时,开一个子线程用于发送请求,子线程中接收到结果或抛出异常时,根据情况给UI线程发送message,最后在UI线程的handler的handleMessage方法中做结果解析和UI更新。这么写虽然简单,但是UI线程和Http请求的耦合度很高,而且代码比较散乱、丑陋。
基于上述几点原因,我设计了一个PostRequest类,用于满足我的http通信需求。我只用到了Post请求,如果你需要Get请求,也可以改写成GetRequest
package com.handspeaker.network;import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.json.JSONObject;
import android.app.Activity; import android.content.Context; import android.net.ConnectivityManager; import android.os.Handler; import android.util.Log;
/** *
用于封装&简化http通信*/ public class PostRequest implements Runnable {
</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">int</span> NO_SERVER_ERROR=1000<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">服务器地址</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">final</span> String URL = "fill your own url"<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">一些请求类型</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">static</span> String ADD = "/add"<span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">static</span> String UPDATE = "/update"<span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">static</span> String PING = "/ping"<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">一些参数</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> connectionTimeout = 60000<span style="color: #000000;">; </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> socketTimeout = 60000<span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">类静态变量</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> HttpClient httpClient=<span style="color: #0000ff;">new</span><span style="color: #000000;"> DefaultHttpClient(); </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> ExecutorService executorService=<span style="color: #000000;">Executors.newCachedThreadPool(); </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> Handler handler = <span style="color: #0000ff;">new</span><span style="color: #000000;"> Handler(); </span><span style="color: #008000;">//</span><span style="color: #008000;">变量</span> <span style="color: #0000ff;">private</span><span style="color: #000000;"> String strResult; </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> HttpPost httpPost; </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> HttpResponse httpResponse; </span><span style="color: #0000ff;">private</span><span style="color: #000000;"> OnReceiveDataListener onReceiveDataListener; </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> statusCode; </span><span style="color: #008000;">/**</span><span style="color: #008000;"> * 构造函数,初始化一些可以重复使用的变量 </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span><span style="color: #000000;"> PostRequest() { strResult </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">; httpResponse </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">; httpPost </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> HttpPost(); } </span><span style="color: #008000;">/**</span><span style="color: #008000;"> * 注册接收数据监听器 * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> listener </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setOnReceiveDataListener(OnReceiveDataListener listener) { onReceiveDataListener </span>=<span style="color: #000000;"> listener; } </span><span style="color: #008000;">/**</span><span style="color: #008000;"> * 根据不同的请求类型来初始化httppost * * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> requestType * 请求类型 * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> nameValuePairs * 需要传递的参数 </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> iniRequest(String requestType, JSONObject jsonObject) { httpPost.addHeader(</span>"Content-Type", "text/json"<span style="color: #000000;">); httpPost.addHeader(</span>"charset", "UTF-8"<span style="color: #000000;">); httpPost.addHeader(</span>"Cache-Control", "no-cache"<span style="color: #000000;">); HttpParams httpParameters </span>=<span style="color: #000000;"> httpPost.getParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, connectionTimeout); HttpConnectionParams.setSoTimeout(httpParameters, socketTimeout); httpPost.setParams(httpParameters); </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { httpPost.setURI(</span><span style="color: #0000ff;">new</span> URI(URL +<span style="color: #000000;"> requestType)); httpPost.setEntity(</span><span style="color: #0000ff;">new</span><span style="color: #000000;"> StringEntity(jsonObject.toString(), HTTP.UTF_8)); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (URISyntaxException e1) { e1.printStackTrace(); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (UnsupportedEncodingException e) { e.printStackTrace(); } } </span><span style="color: #008000;">/**</span><span style="color: #008000;"> * 新开一个线程发送http请求 </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> execute() { executorService.execute(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">); } </span><span style="color: #008000;">/**</span><span style="color: #008000;"> * 检测网络状况 * * </span><span style="color: #808080;">@return</span><span style="color: #008000;"> true is available else false </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">boolean</span><span style="color: #000000;"> checkNetState(Activity activity) { ConnectivityManager connManager </span>=<span style="color: #000000;"> (ConnectivityManager) activity .getSystemService(Context.CONNECTIVITY_SERVICE); </span><span style="color: #0000ff;">if</span> (connManager.getActiveNetworkInfo() != <span style="color: #0000ff;">null</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> connManager.getActiveNetworkInfo().isAvailable(); } </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #000000;">; } </span><span style="color: #008000;">/**</span><span style="color: #008000;"> * 发送http请求的具体执行代码 </span><span style="color: #008000;">*/</span><span style="color: #000000;"> @Override </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() { httpResponse </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">; </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { httpResponse </span>=<span style="color: #000000;"> httpClient.execute(httpPost); strResult </span>=<span style="color: #000000;"> EntityUtils.toString(httpResponse.getEntity()); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (ClientProtocolException e1) { strResult </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">; e1.printStackTrace(); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (IOException e1) { strResult </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">; e1.printStackTrace(); } </span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> { </span><span style="color: #0000ff;">if</span> (httpResponse != <span style="color: #0000ff;">null</span><span style="color: #000000;">) { statusCode </span>=<span style="color: #000000;"> httpResponse.getStatusLine().getStatusCode(); } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { statusCode</span>=<span style="color: #000000;">NO_SERVER_ERROR; } </span><span style="color: #0000ff;">if</span>(onReceiveDataListener!=<span style="color: #0000ff;">null</span><span style="color: #000000;">) { </span><span style="color: #008000;">//</span><span style="color: #008000;">将注册的监听器的onReceiveData方法加入到消息队列中去执行</span> handler.post(<span style="color: #0000ff;">new</span><span style="color: #000000;"> Runnable() { @Override </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() { onReceiveDataListener.onReceiveData(strResult, statusCode); } }); } } } </span><span style="color: #008000;">/**</span><span style="color: #008000;"> * 用于接收并处理http请求结果的监听器 * </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">interface</span><span style="color: #000000;"> OnReceiveDataListener { </span><span style="color: #008000;">/**</span><span style="color: #008000;"> * the callback function for receiving the result data * from post request, and further processing will be done here * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> strResult the result in string style. * </span><span style="color: #808080;">@param</span><span style="color: #008000;"> StatusCode the status of the post </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">abstract</span> <span style="color: #0000ff;">void</span> onReceiveData(String strResult,<span style="color: #0000ff;">int</span><span style="color: #000000;"> StatusCode); }}
代码使用了观察者模式,任何需要接收http请求结果的类,都要实现OnReceiveDataListener接口的抽象方法,同时PostRequest实例调用setOnReceiveDataListener方法,注册该监听器。完整调用步骤如下:
1.创建PostRequest对象,实现onReceiveData接口,编写自己的onReceiveData方法
2.注册监听器
3.调用PostRequest的iniRequest方法,初始化本次request
4.调用PostRequest的execute方法
可能的改进:
1.如果需要多个观察者,可以把只能注册单个监听器改为可以注册多个监听器,维护一个监听器List。
2.如果需求比较简单,并希望调用流程更简洁,iniRequest和execute可以合并
如果有更好的方法或者问题,欢迎随时交流