您的位置:首页 > 理论基础 > 计算机网络

使用android-async-http来封装Android网络请求框架

2016-03-14 21:41 1106 查看
  上一篇为大家讲解了如何《基于Retrofit2.0+RxJava+Dragger2实现不一样的Android网络构架搭建》  http://blog.csdn.net/finddreams/article/details/50849385

  文中有谈到目前Android开发中使用的比较多的网络框架有android-async-http,Volley,OkHttp等,Retrofit2.0就是基于OkHttp的,各大网络框架都有各自的优点,今天讲的android-async-http的优点就是api调用简单,学习成本低,jar包的体积小等。

概述:

  android-async-http是一个基于Apache的HttpClient的异步的Android请求框架,所有的请求全在UI(主)线程之外执行,而callback成功失败的回调都是在主线程中执行。

  

 Github地址: https://github.com/loopj/android-async-http

特点:

使用HttpClient 4.3.6版本而不是Android 提供的DefaultHttpClient;

兼容安卓API 23(6.0)和更高的版本;

库很小,jar包小于100K;

支持重试机制;

cookie的管理,内部实现用的是Android的SharedPreferences;

通过BaseJsonHttpResponseHandler和各种json库集成;

……………

核心类介绍:

AsyncHttpResponseHandler ——这是一个请求返回处理,成功,失败,开始,完成,等自定义处理请求的类;

BinaryHttpResponseHandler extends AsyncHttpResponseHandler ——继承AsyncHttpResponseHandler的子类,这是一个字节流返回处理的类, 该类用于处理图片,流的形式;

JsonHttpResponseHandler extends AsyncHttpResponseHandler ——继承AsyncHttpResponseHandler的子类,这是一个json请求返回处理服务器与客户端用json交流时使用的类;

AsyncHttpRequest implements Runnable ——基于线程的子类,用于 异步请求类, 通过AsyncHttpResponseHandler回调。

TextHttpResponseHandler 是把字节流转成了字符串文本的形式,方便使用;

PersistentCookieStore implements CookieStore ——这是一个基于CookieStore的子类, 使用SharedPreferences来保存Cookie数据,并具备添加清楚Cookie的功能。

RequestParams 封装了请求参数的类,是键值对的形式,相当于HashMap。有add和put方法,add方法的值只能是String,而put方法的值则可以添加很多的其他数据类型;



使用方法:

   1. 引入到咱们的项目中,目前的最新版本是1.4.9,解决了Android6.0以上HttpClient的不兼容问题,请使用最新的版本:

compile 'com.loopj.android:android-async-http:1.4.9'


  引入之后我们发现依赖库中不只有android-async-http:1.4.9.jar还多了一个叫httpclient 4.3.6.jar的包,这是什么原因了?

  

  HttpClient和HttpURLConnection都很熟悉了,HttpClient 的API实现起来简单,HttpURLConnection则比较麻烦一点。Android 2.2版本之前因为HttpURLConnection存在一些bug,所以谷歌官方推荐使用HttpClient,但是后来慢慢修正了HttpURLConnection的问题, google 不再维护 HttpClient 了,以致于Android5.1里面已经把 HttpClient 标注为过期。所有Android4.0之后应该用HttpURLConnection来作为网络请求,这个想必大家都已经知道了。

  

  所以为了修复android-async-http这个网络库对于高版本(API大于23)的android系统存在不兼容的问题,他们引入了http client这个开源的网络库,那样就可以继续使用android-async-http在Android上开发了,因为已经兼容了安卓API 23(6.0)和更高的版本,所以大可放心使用。

  2.用单例模式封装一下AsyncHttpClient,方便调用管理:

/**
* AsyncHttpClientUtils的单例
*
* @Author finddreams
* @Address http://blog.csdn.net/finddreams * @Time 2016/3/14
*/
public class AsyncHttpClientUtils {
public static final String TAG = AsyncHttpClientUtils.class.getSimpleName();
public static final int SOCKET_TIMEOUT = 20 * 1000;//默认超时时间
//   public static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000;
private static AsyncHttpClientUtils instance = new AsyncHttpClientUtils();
// 实例话对象
private static AsyncHttpClient client = new AsyncHttpClient();

static {
//        client.setConnectTimeout(SOCKET_TIMEOUT);  //连接时间
//        client.setResponseTimeout(SOCKET_TIMEOUT); //响应时间
client.setTimeout(SOCKET_TIMEOUT); // 设置连接超时,如果不设置,默认为10s
}

private PersistentCookieStore cookieStore;

private AsyncHttpClientUtils() {

}

public static AsyncHttpClientUtils getInstance() {
return instance;
}

public AsyncHttpClient getAsyncHttpClient() {
return client;
}

/**
* get方法带参数
*/
public RequestHandle get(String url, RequestParams params,
HttpCallBack httpCallBack) {
Log.i(TAG, client.getUrlWithQueryString(true, url, params));
RequestHandle requestHandle = client.get(url, params, httpCallBack);
return requestHandle;
}

/**
* post请求,带参数
*/
public RequestHandle post(String url, RequestParams params,
HttpCallBack httpCallBack) {
Log.i(TAG, client.getUrlWithQueryString(true, url, params));
RequestHandle requestHandle = client.post(url, params, httpCallBack);
return requestHandle;
}

/**
* 设置Cookie
*
* @param context
*/
public void setCookie(Context context) {
cookieStore = new PersistentCookieStore(context);
client.setCookieStore(cookieStore);
}

/**
* 清楚Cookie
*/
public void clearSession() {
if (cookieStore != null) {
cookieStore.clear();
}
}

/**
* 设置重试机制
*/
public void setRetry() {
client.setMaxRetriesAndTimeout(2, SOCKET_TIMEOUT);
client.allowRetryExceptionClass(SocketTimeoutException.class);
client.blockRetryExceptionClass(SSLException.class);
}

/**
* 取消所有请求
*
* @param context
*/
public void cancelAllRequests(Context context) {
if (client != null) {
Log.i(TAG, "cancel");
client.cancelRequests(context, true); //取消请求
client.cancelAllRequests(true);
}
}

/*
* 文件下载
*
* @param paramString
* @param paramBinaryHttpResponseHandler
*/
public void downFile(String paramString,
BinaryHttpResponseHandler paramBinaryHttpResponseHandler) {
try {
client.get(paramString, paramBinaryHttpResponseHandler);
return;
} catch (IllegalArgumentException localIllegalArgumentException) {
Log.d("hhxh", "URL路径不正确!!");
}
}

}


   client.setTimeout(SOCKET_TIMEOUT); // 设置连接超时时间,如果不设置,AsyncHttpClient默认的超时时间为为10s,如果我们的用户量过大,服务器处理请求所需要的时间比较多的话,可以增加超时时间,不要使用默认的。

public static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000;


  setCookie()方法中新建一个PersistentCookieStore类来管理AsyncHttpClient请求中的Cookie,

PersistentCookieStore是可自动将cookie保存到Android设备的SharedPreferences中,如果你的项目中使用cookie来管理验证会话,验证请求权限的话,这个非常简单有用,因为cookie信息已经持久化在SharedPreferenceswen文件中,就算是退出了,你的登录信息还是会保持一段有效时间。

  setRetry()方法中可以设置重试机制。client.setMaxRetriesAndTimeout(2, SOCKET_TIMEOUT)方法的参数一是重试的次数,第二个是重试的时间;

client.allowRetryExceptionClass(SocketTimeoutException.class);
client.blockRetryExceptionClass(SSLException.class);


  client.allowRetryExceptionClass(SocketTimeoutException.class)是设置出现异常的后重试的白名单,意思是当网络异常是SocketTimeoutException则可以重试。

public static void allowRetryExceptionClass(Class<?> cls) {
if (cls != null) {
RetryHandler.addClassToWhitelist(cls);
}
}


   client.blockRetryExceptionClass(SSLException.class);则是添加重试机制的黑名单,当出现SSLException异常的时候,则网络请求不会重连。

   

  class RetryHandler implements HttpRequestRetryHandler 类的源码中,默认NoHttpResponseException,UnknownHostException,SocketException都是在白名单;而InterruptedIOException,SSLException则默认是添加在黑名单中,不会重连。

private final static HashSet<Class<?>> exceptionWhitelist = new HashSet<Class<?>>();
private final static HashSet<Class<?>> exceptionBlacklist = new HashSet<Class<?>>();

static {
// Retry if the server dropped connection on us
exceptionWhitelist.add(NoHttpResponseException.class);
// retry-this, since it may happens as part of a Wi-Fi to 3G failover
exceptionWhitelist.add(UnknownHostException.class);
// retry-this, since it may happens as part of a Wi-Fi to 3G failover
exceptionWhitelist.add(SocketException.class);

// never retry timeouts
exceptionBlacklist.add(InterruptedIOException.class);
// never retry SSL handshake failures
exceptionBlacklist.add(SSLException.class);
}


  Log.i(TAG, AsyncHttpClient.getUrlWithQueryString(true, url, params));

  client.getUrlWithQueryString(true, url, params)

  这个方法可以把请求中的url和请求参数作为String返回,方便我们调试;比如:  

 I/AsyncHttpClientUtils: http://apis.baidu.com/apistore/weatherservice/cityname?cityname=北京[/code] 
  

  3.请求的响应处理Handler 有很多种BinaryHttpResponseHandler,JsonHttpResponseHandler,TextHttpResponseHandler他们都是继承自AsyncHttpResponseHandler,TextHttpResponseHandler使用起来很简单:

private TextHttpResponseHandler responseHandler =  new TextHttpResponseHandler(){
@Override
public void onStart() {
Log.e(tag, "onStart====");
}

@Override
public void onSuccess(int statusCode, Header[] headers, String response) {
Log.e(tag, response);
}

@Override
public void onFailure(int statusCode, Header[] headers, String errorResponse, Throwable e) {

}

};


  TextHttpResponseHandler直接把字节流包装成String来返回,使用起来也很方便;

  

  4.前面说BaseJsonHttpResponseHandler 是可以集成各自json库,看到这句话,有很多人可能不知道是如何做到的,下面就是集成了Gson库的解析类:

/**
* 基于BaseJsonHttpResponseHandler封装的Gson泛型解析
*
* @author finddreams
* @address http://blog.csdn.net/finddreams */
public abstract class HttpCallBack<T> extends BaseJsonHttpResponseHandler<T> {
@Override
public abstract void onSuccess(int statusCode, Header[] headers, String rawJsonResponse, T response);

@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, String rawJsonData, T errorResponse) {
Log.i("onFailure", throwable.getMessage());
}

@Override
public void onStart() {
super.onStart();
}

@Override
public void onFinish() {
super.onFinish();
}

@Override
public void onUserException(Throwable error) {
super.onUserException(error);
}

@Override
protected T parseResponse(String rawJsonData, boolean isFailure) throws Throwable {
Log.i("rawJsonData", rawJsonData);
Log.i("isFailure", isFailure + "");

T t = new Gson().fromJson(rawJsonData, getSuperclassTypeParameter(getClass()));

return t;
}

/**
* 返回gson类型
*/
public static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}

}


  HttpCallBack这个类来做为请求的回调,就可以通过泛型的方式,你想把请求的结果解析成什么类就会返回什么类,这样使用起来就方便了很多。

5.最后还是用百度api提供的天气接口,来实现AsyncHttpClientget请求的调用:

public class MainActivity extends AppCompatActivity {

@Bind(R.id.content)
EditText content;
@Bind(R.id.getresult)
Button getresult;
@Bind(R.id.result)
TextView result;
public static String BaiduUrl = "http://apis.baidu.com/apistore/weatherservice/cityname";  //百度api地址
public static String baiduKey = "";  //百度申请的apikey
private AsyncHttpClientUtils clientUtils;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
clientUtils = AsyncHttpClientUtils.getInstance();
}

@OnClick(R.id.getresult)
public void onClick(View view) {
getQueryResult();
}

private void getQueryResult() {
RequestParams params = new RequestParams();
AsyncHttpClient client = clientUtils.getAsyncHttpClient();
client.addHeader("apikey", MainActivity.baiduKey);
params.add("cityname", content.getText().toString());
RequestHandle requestHandle = clientUtils.get(BaiduUrl, params, new HttpCallBack<WeatherResultBean>() {
@Override
public void onSuccess(int statusCode, Header[] headers, String rawJsonResponse, WeatherResultBean response) {
WeatherResultBean.RetDataEntity retData = response.getRetData();
result.setText(retData.getCity() + ":" + retData.getWeather() + ":" + retData.getDate());
}

@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, String rawJsonData, WeatherResultBean errorResponse) {
super.onFailure(statusCode, headers, throwable, rawJsonData, errorResponse);
}
});

//        requestHandle.cancel(true);//取消单个请求,
//        clientUtils.cancelAllRequests(this); //取消所有请求
}
}


  是不是调用起来非常的简单,不用太多的封装,非常快速的就可以完成get,post请求的调用,很适合一些中小项目的敏捷开发,而且android-async-http的jar包体积非常的小,对于apk的体积大小来说,基本上可以忽略。

  同时android-async-http的api很简单,结构清晰,比较适合深入研究。还有很多实用的功能等待大家去探索,比如本文没有讲的文件上传与下载,HTTP Basic Auth身份认证等等; 

  

  最后把运行的结果图附上,调用的百度天气api接口,实现天气查询功能:

  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: