async-http-client开源库学习笔记(一)

邹阳
2023-12-01

0. 文前闲话

    作为一个Android开发的大龄初学者,面对扑面而来的各种姿势的Android的开源组件,让人倍感窒息,难以应对。无奈为了养家糊口,虽然已近不惑,人老珠黄,也只能废寝忘食,逐个体位细细揣摩研究,不断以身实践,争取早日小成。

    话说那是一个阳光明媚的下午,我坐在街口转角处优雅的网络会所里,品着一杯上好的Coca-Cola,研读着oschina客户端源码,身旁不时传来:“一起上搞死他,他没蓝了...!”。

    从火蚁(oschina客户端的开发者之一,向他们致敬)那里知道了async-http-client开源库,为了千千万万个没过英语四级的程序猿GG,就在这里翻译个作者写的"用户说明书"先...

1. async-http-client开源库简介

    async-http-client库是一个基于回调函数的Http异步通信客户端Android组件,是在Apache的HttpClient库的基础上开发构建而成的。这里的异步,是指它所有的网络请求都是在app的UI线程之外的独立工作线程中执行。而开发者通过利用Android的消息处理机制,把我们所需要编写的回调函数放在这个回调函数的创建线程中执行(一般就是UI线程),所以使用起来非常方便,有了它,Boss再也不用担心我被多线程同步搞死了。除了能应用在开发普通App上,还可以用来开发Service或后台线程,async-http-client库可以自已分辨是被用在哪一种应用下,不需要额外的设置。

1.1 特点

  • 异步方式发起Http请求,可以使用匿名回调函数处理网络应答;

  • 在UI主线程之外的工作线程发起Http请求;

  • 通过使用线程池解决了资源并发的效率问题;

  • 通过使用RequestParams类,可完成GET/POST的参数构建

  • 支持文件的分段下载功能;

  • 支持上传JSON数据流

  • 对重定向循环、重定向相对路径异常进行了处理

  • 代码体积小,全部功能只占90kb;

  • 专门针对移动网络的不稳定性,对请求重发进行了优化,实现了自动智能处理;

  • 传输时支持数据压缩,可自动对应答进行gzip解压处理;

  • 使用BinaryHttpResponseHandler可进行较底层的tcp/ip协议数据通信;

  • JsonHttpResponseHandler内嵌JSON语法分析功能,可完成JSON数据解析;

  • FileAsyncHttpResponseHandler可直接将应答保存到本地文件中;

  • 支持cookie的持久化,可使用App的SharedPreferences保存cookie信息;

  • 通过BaseJsonHttpResponseHandler可与Jackson JSON, Gson等第三方JSON框架库集成;

  • SaxAsyncHttpResponseHandler支持SAX语法分析

  • 除了UTF-8,还支持其它语言编码。

1.2 使用async-http-client的大型应用

  • Instagram

  • Pinterest

  • Frontline Commando (Glu Games)

  • Heyzap

  • Pose

(以上应用我一个都没用过,反正说明async-http-client很diao就对了)

2. async-http-client库的安装和基本应用

2.1 基本应用方法

    1. 在Gradle build脚本中增加

dependencies {
    compile 'com.loopj.android:android-async-http:1.4.8'
}

    2. 引入http包

import com.loopj.android.http.*;

    3. 创建AsyncHttpClient 实例,并发出请求

AsyncHttpClientclient = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler(){
    @Override
    public void onStart(){
        // called before request is started
    }
    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] response){
        // called when response HTTP status is "200 OK"
    }
    @Override
    public void onFailure(int statusCode, Header[] headers,
                          byte[] errorResponse, Throwablee){
        // called when response HTTP status is "4XX" (eg. 401, 403, 404)
    }
    @Override
    public void onRetry(int retryNo){
        // called when request is retried
    }
});

2.2 推荐使用方法:创建静态Http客户端

    创建AsyncHttpClient的静态实例进行通信更加方便,以使用Twitter提供的Api为例(此处使用Twitter作例子,站在大墙里面的我们看看就行了):

import com.loopj.android.http.*;

public class TwitterRestClient {
    private static final String BASE_URL = "https://api.twitter.com/1/";

    private static AsyncHttpClient client = new AsyncHttpClient();

    public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.get(getAbsoluteUrl(url), params, responseHandler);
    }

    public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.post(getAbsoluteUrl(url), params, responseHandler);
    }

    private static String getAbsoluteUrl(String relativeUrl) {
        return BASE_URL + relativeUrl;
    }
}

    TwitterRestClient 类中创建了一个AsyncHttpClient的静态实例,通过静态实例与Twitter进行数据通信,共有两个对外的接口函数get,set,也都是静态的。下面是如何在代码中使用这个类:

import org.json.*;
import com.loopj.android.http.*;

class TwitterRestClientUsage {
    public void getPublicTimeline() throws JSONException {
        TwitterRestClient.get("statuses/public_timeline.json", null, 
                new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, 
                    JSONObject response) {
                // If the response is JSONObject instead of expected JSONArray
            }

            @Override
            public void onSuccess(int statusCode, Header[] headers, 
                    JSONArray timeline) {
                // Pull out the first event on the public timeline
                JSONObject firstEvent = timeline.get(0);
                String tweetText = firstEvent.getString("text");

                // Do something with the response
                System.out.println(tweetText);
            }
        });
    }
}

    这里使用了匿名回调函数,并且是JsonHttpResponseHandler类型,它内嵌了Json语言解析器,可直接在处理函数中使用对应答数据解析后的Json数据,真是即方便又快捷。

3. 使用PersistentCookieStore进行Cookie的持久化存储

    async-http-client库包含一个PersistentCookieStore类,这个类实现了CookieStore接口(源自Apache HttpClient包),可自动将cookie信息保存到应用的SharedPreferences储存中。

    如果你的应用需要使用cookie维护用户授权session,这是非常有用,方便的。即使关闭了app或重新启动app,应用也可以保持用户已登录的状态。

    首先创建一个AsyncHttpClient实例:

AsyncHttpClient myClient = new AsyncHttpClient();

    为这个实例设置一个新建的PersistentCookieStore的实例以进行cookie存储,调用这个PersistentCookieStore实例的构造函数时,使用一个activity或application context作参数(一般用this就可以了):

PersistentCookieStore myCookieStore = new PersistentCookieStore(this);
myClient.setCookieStore(myCookieStore);

    这样由服务端接收到的cookie将会自动存储在你的android设备上。如果要添加自己的cookie,只需要构建一个新的cookie并调用addCookie函数:

BasicClientCookie newCookie = new BasicClientCookie("cookiesare", "awesome");
newCookie.setVersion(1);
newCookie.setDomain("mydomain.com");
newCookie.setPath("/");
myCookieStore.addCookie(newCookie);

4. 使用RequestParams增加GET/POST参数

4.1 为请求增加参数

    大部分应用的url请求都需要带各种参数,在Get/Post请求时增加参数,可使用RequestParams类。

    可以使用以下三种方法构建RequestParams实例:

    1. 创建一个空的RequestParams实例,并增加参数:

RequestParams params = new RequestParams();
params.put("key", "value");
params.put("more", "data");

    2. 只有一个参数,创建RequestParams实例:

RequestParams params = new RequestParams("single", "value");

    3. 利用已存在的Map键值对创建RequestParams实例:

HashMap<String, String> paramMap = new HashMap<String, String>();
paramMap.put("key", "value");
RequestParams params = new RequestParams(paramMap);

4.2 利用RequestParams上传文件

    RequestParams类还可以用来实现文件分段上传,有以下三种实现方式:

    1. 将InputStream作为参数加入RequestParams:

InputStream myInputStream = blah;
RequestParams params = new RequestParams();
params.put("secret_passwords", myInputStream, "passwords.txt");

    2. 直接将File对象增加到RequestParams中:

File myFile = new File("/path/to/file.png");
RequestParams params = new RequestParams();
try {
    params.put("profile_picture", myFile);
} catch(FileNotFoundException e) {}

    3. 使用二进制字节数组:

byte[] myByteArray = blah;
RequestParams params = new RequestParams();
params.put("soundtrack", new ByteArrayInputStream(myByteArray), "she-wolf.mp3");

5. 使用FileAsyncHttpResponseHandler下载二进制数据

    FileAsyncHttpResponseHandler用来获取二进制数据,比如图像、声音等文件。

AsyncHttpClient client = new AsyncHttpClient();
client.get("https://example.com/file.png", 
        new FileAsyncHttpResponseHandler(/* Context */ this) {
    @Override
    public void onSuccess(int statusCode, Header[] headers, File response) {
        // Do something with the file `response`
    }
});

6. 为HTTP通信增加授权认证

    在实际应用环境中,某些服务器资源需要用户名/密码授权认证才能访问,这类资源访问需要使用HTTP Basic Access Authentication协议,请求才能被处理。可以使用setBasicAuth函数提供认证信息。

    为主机或域名访问设置用户名/密码,默认状态认证信息对所有主机、端口或域名有效。

AsyncHttpClient client = new AsyncHttpClient();
client.setBasicAuth("username","password/token");
client.get("https://example.com");

    更为推荐的方式是对特定的主机或端口提供授权认证信息:

AsyncHttpClient client = new AsyncHttpClient();
client.setBasicAuth("username","password", 
        new AuthScope("example.com", 80, AuthScope.ANY_REALM));
client.get("https://example.com");

 类似资料: