async-http-client开源库学习笔记

jopen 9年前

在进行Android应用开发时,网络通信功能是不可或缺的模块之一。为了能让应用保持好的用户交互体验和高效的网络通信性能,程序员GG要进行大量的多线程开发以及线程之间的并发同步处理,稍有不慎,伤得可就不仅仅是测试软妹子的心,还有可能是自己的饭碗。 async-http-client开源库为程序员GG封装了http数据通信的各种底层处理,包括异步、数据转换、文件分段下载等等,我们只需要关注功能的本身所需要的数据处理部分就可以安心泡妹子了。

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线程),所以使用起来非常方便,有了它,妈妈再也不用担心我被多线程同步搞死了。除了能应用在开发普通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的静态实例进行通信更加方便,以使用推ter提供的Api为例(此处使用推ter作例子,站在大墙里面的我们看看就行了):

import com.loopj.android.http.*;    public class 推terRestClient {      private static final String BASE_URL = "https://api.推ter.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;      }  }

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

import org.json.*;  import com.loopj.android.http.*;    class 推terRestClientUsage {      public void getPublicTimeline() throws JSONException {          推terRestClient.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");

来自:http://my.oschina.net/u/725054/blog/494494