android-async-http使用

android-async-http是基于Apache HttpClient专门用于android的异步http请求,所有的请求都在非UI线程执行。API比较全面,使用比较简单,而且在CallBack中使用了Handler消息机制,我们可以在回调方法onSuccess,onFailure等中直接对UI进行操作。


GIT官方源码:https://github.com/loopj/android-async-http

官方使用教程:http://loopj.com/android-async-http/


我们通过官方教程首先来了解下其相关特性:

1,用HttpClient代替Android提供的DefaultHttpClient;

2,兼容Android API 23以及更高;

3,发送异步http请求,在匿名的callback对象中处理response信息;

4,在非UI线程执行http请求;

5,使用线程池处理并发请求;

6,RequestParams作为GET/POST参数构造器;

7,多部件文件上传,不需要引入第三方库;

8,JSON数据流上传,不需要引入库;

9,能处理循环行和相对重定向;

10,对应用来说库很小,总共只有90KB;

11,使多种多样的移动连接具备良好自动智能请求重试机制;

12,支持超快速请求的自动gzip响应解码;

13,BinaryHttpResponseHandler支持二进制通讯协议;

14,通过JsonHttpResponseHandler实现内置解析response成JSON格式;

15,通过FileAsyncHttpResponseHandler实现直接将response写入保存到文件中;

16,持久化的cookie存储,将cookie保存到应用程序的SharePreferences中;

17,通过BaseJsonHttpResponseHandler集成Jackson Json,Gson和其他的JSON序列化库;

18,通过SaxAsyncHttpResponseHandler支持SAX解析;

19,支持各种语言和内容编码,不是只有UTF-8;


集成方法:

在GIT源码中有介绍,这里不详细说,我们这里用的Android studio,只要在app/build.gradle文件加上:

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


使用步骤:

1,创建AsyncHttpClient对象;

2,如果需要参数,可以创建RequestParams对象添加参数,如果不需要参数,这一步可免;

3,按需要调用AsyncHttpClient的某个GET/POST的方法,传递需要的callback接口实现。


基础体验:

首先给出一个官方教程的建议,封装静态的HttpClient:

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

  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;
  }
  ......
}
这样封装好了使用起来特别方便:

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);
            }
        });
    }
}
以上内容来自官方教程,详细请看官方文档

每次请求都需要传递一个实现ResponseHandlerInterface接口的实例,用来接收处理回调的事件,一般都继承AsyncHttpResponseHandler。

1,首先看下AsyncHttpResponseHandler:

                RequestParams params = new RequestParams();
                TestHttpClient.get(AsyncHttpActivity.this, url, params, new AsyncHttpResponseHandler() {
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {

                    }

                    @Override
                    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {

                    }
                });
可以看出,返回的结果是byte类型的,可以转换成我们需要的格式。默认重写了onSuccess和onFailure两个方法,还可以重写onStart、onFinish、onCancle、onRetry等方法来实现数据的获取以及与界面的交互效果。


,2,BinaryHttpResponseHandler继承自AsyncHttpResponseHandler,可以发送二进制请求,如请求图片等:

                RequestParams params = new RequestParams();
                TestHttpClient.get(AsyncHttpActivity.this, url, params, new BinaryHttpResponseHandler() {
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) {

                    }

                    @Override
                    public void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error) {
                        
                    }
                });
这里返回给我们的也是byte类型,我们可以转换成Bitmap等。


3,TextHttpResponseHandler,继承自AsyncHttpResponseHandler,只重写了onSuccess和onFailure两个方法。

                RequestParams params = new RequestParams();
                TestHttpClient.get(AsyncHttpActivity.this, url, params, new TextHttpResponseHandler() {
                    @Override
                    public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {

                    }

                    @Override
                    public void onSuccess(int statusCode, Header[] headers, String responseString) {
                        
                    }
                });
返回的结果由原来的byte类型转换成了String类型。

4,JsonHttpResponseHandler,继承自TextHttpResponseHandler,同样只重写了onSuccess和onFailure两个方法。

               RequestParams params = new RequestParams();
                TestHttpClient.get(AsyncHttpActivity.this, url, params, new JsonHttpResponseHandler(){
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
                        super.onSuccess(statusCode, headers, response);
                    }
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
                        super.onSuccess(statusCode, headers, response);
                    }
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, String responseString) {
                        super.onSuccess(statusCode, headers, responseString);
                    }

                    @Override
                    public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                        super.onFailure(statusCode, headers, responseString, throwable);
                    }
                    @Override
                    public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
                        super.onFailure(statusCode, headers, throwable, errorResponse);
                    }
                    @Override
                    public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
                        super.onFailure(statusCode, headers, throwable, errorResponse);
                    }
                });
这里有三个onSuccess和onFailure方法供重写,返回的结果分别转换成JSONObject、JSONArray和String类型。按照不同的返回值类型调用不同的方法,这个比较烦。


5,BaseJsonHttpResponseHandler,继承自TextHttpResponseHandler,同样只重写了onSuccess、onFailure两个方法,另外添加了一个方法parseResponse。

                RequestParams params = new RequestParams();
                TestHttpClient.get(AsyncHttpActivity.this, url, params, new BaseJsonHttpResponseHandler<Object>() {
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, String rawJsonResponse, Object response) {

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

                    }
                    @Override
                    protected Object parseResponse(String rawJsonData, boolean isFailure) throws Throwable {
                        return null;
                    }
                });

首先要说明,在AsyncHttpResponseHandler中onSuccess和onFailure通过handler消息机制的处理,可以直接在方法体中操作UI更新,但是在parseResponse方法中是不可以直接操作UI更新的。

这里我们借助源码学习下参数和方法的调用:

    /**
     * Should return deserialized instance of generic type, may return object for more vague
     * handling
     *
     * @param rawJsonData response string, may be null
     * @param isFailure   indicating if this method is called from onFailure or not
     * @return object of generic type or possibly null if you choose so
     * @throws Throwable allows you to throw anything from within deserializing JSON response
     */
    protected abstract JSON_TYPE parseResponse(String rawJsonData, boolean isFailure) throws Throwable;
能返回泛型的反序列化实例,也可以返回更多模糊处理的对象。第一个参数rawJsonData是response字符串,第二个参数isFailure判断是否被onFailure方法调用。

    @Override
    public final void onSuccess(final int statusCode, final Header[] headers, final String responseString) {
        if (statusCode != HttpStatus.SC_NO_CONTENT) {
            Runnable parser = new Runnable() {
                @Override
                public void run() {
                    try {
                        final JSON_TYPE jsonResponse = parseResponse(responseString, false);
                        postRunnable(new Runnable() {
                            @Override
                            public void run() {
                                onSuccess(statusCode, headers, responseString, jsonResponse);
                            }
                        });
                    } catch (final Throwable t) {
                        AsyncHttpClient.log.d(LOG_TAG, "parseResponse thrown an problem", t);
                        postRunnable(new Runnable() {
                            @Override
                            public void run() {
                                onFailure(statusCode, headers, t, responseString, null);
                            }
                        });
                    }
                }
            };
            if (!getUseSynchronousMode() && !getUsePoolThread()) {
                new Thread(parser).start();
            } else {
                // In synchronous mode everything should be run on one thread
                parser.run();
            }
        } else {
            onSuccess(statusCode, headers, null, null);
        }
    }
可以看出onSuccess的第三个参数responseString就是好返回的response字符串,和parseResponse方法的第一个参数值一样,onSuccess的第四个参数是在parseResponse方法处理后的返回值。

    @Override
    public final void onFailure(final int statusCode, final Header[] headers, final String responseString, final Throwable throwable) {
        if (responseString != null) {
            Runnable parser = new Runnable() {
                @Override
                public void run() {
                    try {
                        final JSON_TYPE jsonResponse = parseResponse(responseString, true);
                        postRunnable(new Runnable() {
                            @Override
                            public void run() {
                                onFailure(statusCode, headers, throwable, responseString, jsonResponse);
                            }
                        });
                    } catch (Throwable t) {
                        AsyncHttpClient.log.d(LOG_TAG, "parseResponse thrown an problem", t);
                        postRunnable(new Runnable() {
                            @Override
                            public void run() {
                                onFailure(statusCode, headers, throwable, responseString, null);
                            }
                        });
                    }
                }
            };
            if (!getUseSynchronousMode() && !getUsePoolThread()) {
                new Thread(parser).start();
            } else {
                // In synchronous mode everything should be run on one thread
                parser.run();
            }
        } else {
            onFailure(statusCode, headers, throwable, null, null);
        }
    }
onFailure的第四个参数是response字符串,第五个参数是parseResponse方法处理后的返回值,第三个参数是抛出的异常。

BaseJsonHttpResponseHandler需要自己对返回的值进行处理,内容解析。


6,FileAsyncHttpResponseHandler,可以实现将response写入保存到文件中:

                RequestParams params = new RequestParams();
                TestHttpClient.get(AsyncHttpActivity.this, url, params, new FileAsyncHttpResponseHandler(AsyncHttpActivity.this) {
                    @Override
                    public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) {

                    }
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, File file) {

                    }
                });
从参数可以看出,返回给我们的直接是File,内容已经写入到File中了。 创建FileAsyncHttpResponseHandler实例的时候,我们这里传了this参数,参考源码:

     /**
     * Obtains new FileAsyncHttpResponseHandler against context with target being temporary file
     *
     * @param context Context, must not be null
     */
    public FileAsyncHttpResponseHandler(Context context) {
        super();
        this.file = getTemporaryFile(context);
        this.append = false;
        this.renameIfExists = false;
    }
这里会掉getTemporaryFile方法获得File。

     /**
     * Used when there is no file to be used when calling constructor
     *
     * @param context Context, must not be null
     * @return temporary file or null if creating file failed
     */
    protected File getTemporaryFile(Context context) {
        Utils.asserts(context != null, "Tried creating temporary file without having Context");
        try {
            return File.createTempFile("temp_", "_handled", context.getCacheDir());
        } catch (IOException e) {
            AsyncHttpClient.log.e(LOG_TAG, "Cannot create temporary file", e);
        }
        return null;
    }
该方法中,会创建一个默认的File。

当然我们也可以自己创建指定的File,实例化的时候传过去:

     /**
     * Obtains new FileAsyncHttpResponseHandler and stores response in passed file
     *
     * @param file File to store response within, must not be null
     */
    public FileAsyncHttpResponseHandler(File file) {
        this(file, false);
    }
该构造方法直接传了File。

     /**
     * Obtains new FileAsyncHttpResponseHandler and stores response in passed file
     *
     * @param file   File to store response within, must not be null
     * @param append whether data should be appended to existing file
     */
    public FileAsyncHttpResponseHandler(File file, boolean append) {
        this(file, append, false);
    }
该构造犯法多传一个参数boolean append,用于判断是否将数据追加到已经存在的File中,如果是true不会覆盖原来内容,加在后面,是false就覆盖。

     /**
     * Obtains new FileAsyncHttpResponseHandler and stores response in passed file
     *
     * @param file                     File to store response within, must not be null
     * @param append                   whether data should be appended to existing file
     * @param renameTargetFileIfExists whether target file should be renamed if it already exists
     */
    public FileAsyncHttpResponseHandler(File file, boolean append, boolean renameTargetFileIfExists) {
        this(file,append,renameTargetFileIfExists,false);
    }
多一个参数boolean renameTargetFileIfExists,用于判断当文件已经存在的时候是否重命名文件。

     /**
     * Obtains new FileAsyncHttpResponseHandler and stores response in passed file
     *
     * @param file                     File to store response within, must not be null
     * @param append                   whether data should be appended to existing file
     * @param renameTargetFileIfExists whether target file should be renamed if it already exists
     * @param usePoolThread Whether to use the pool's thread to fire callbacks
     */
    public FileAsyncHttpResponseHandler(File file, boolean append, boolean renameTargetFileIfExists,boolean usePoolThread) {
        super(usePoolThread);
        Utils.asserts(file != null, "File passed into FileAsyncHttpResponseHandler constructor must not be null");
        if (!file.isDirectory() && !file.getParentFile().isDirectory()) {
            Utils.asserts(file.getParentFile().mkdirs(), "Cannot create parent directories for requested File location");
        }
        if (file.isDirectory()) {
            if (!file.mkdirs()) {
                AsyncHttpClient.log.d(LOG_TAG, "Cannot create directories for requested Directory location, might not be a problem");
            }
        }
        this.file = file;
        this.append = append;
        this.renameIfExists = renameTargetFileIfExists;
    }
这里多一个参数boolean usePoolThread,是否使用线程池里面的线程实现回调,默认是false,如果是true的话,就不会调用封装好的Looper和Handler实现数据的处理和回调。


7,SaxAsyncHttpResponseHandler,继承自AsyncHttpResponseHandler,可以进行SAX解析。

                RequestParams params = new RequestParams();
                DefaultHandler dh = new DefaultHandler();
                TestHttpClient.get(AsyncHttpActivity.this, url, params, new SaxAsyncHttpResponseHandler<DefaultHandler>(dh) {
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, DefaultHandler defaultHandler) {

                    }
                    @Override
                    public void onFailure(int statusCode, Header[] headers, DefaultHandler defaultHandler) {

                    }
                });

实例化SaxAsyncHttpResponseHandler的时候传递参数和返回的类型需要继承自DefaultHandler,然后通过DefaultHandler实例进行sax解析。


Cookie持久化存储:

这里使用PersistentCookieStore实现持久化存储,实现Apche HttpClient CookieStore接口,cookies保存到SharePreferences中。

首先创建一个AsyncHttpClient实例:

AsyncHttpClient client = new AsyncHttpClient();
然后set client的cookie store为一个PersistentCookieStore实例,构造函数传入参数Activity或者Application context。

        PersistentCookieStore cookieStore = new PersistentCookieStore(this);
        client.setCookieStore(cookieStore);
任何从服务器获取的cookie都会被存到这个持久化的cookie store中,需要添加自己的cookie到store中,只需要构造一个新的cookie,掉用addCookie方法就可以了。

        BasicClientCookie cookie = new BasicClientCookie("testName","testValue");
        cookie.setVersion(1);
        cookie.setDomain("mydomain.com");
        cookie.setPath("/");
        cookieStore.addCookie(cookie);


RequestParams给GET/POST请求添加参数:

RequestParams可以通过不同的方式来创建实例,创建一个空的RequestParams,添加参数:

        RequestParams params = new RequestParams();
        params.put("name","tome");
        params.put("age","22");

创建带单个参数实例:

        RequestParams params = new RequestParams("singleParam","value");
通过一个已存在的键/值Map来创建:

        Map<String,Object> map = new HashMap<String,Object>();
        map.put("name","Tom");
        RequestParams params = new RequestParams(map);

RequestParams上传文件:

支持多种文件上传,RequestParams上传InputStream:

        InputStream in = ....;
        RequestParams params = new RequestParams();
        params.put("secrect_password",in,"password.txt");
这里put三个参数分别是:key;InputStream;InputStream的name。


RequestParams上传File对象:

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


RequestParams上传字节数组:

        byte [] newByte = ...;
        RequestParams params = new RequestParams();
        params.put("key",new ByteArrayInputStream(newByte),"test.mp3");

以上是对该网络请求框架阅读官方教程后的一些了解,有什么不足之处还望指点。



猜你喜欢

转载自blog.csdn.net/liujibin1836591303/article/details/72639404