安卓网络请求框架第三弹——OkHttp的封装

概述:此篇为Android网络请求框架第三弹,底层请求用的是okhttp 基本机构来自包建强老师的app研发录,在研发录中,包老师使用的是HttpClient,但是由于google在Android4.0之后删除了HttpClient的APi,所以在包老师的基础,加以修改,使用okHttp作为请求方式。建议没读过包老师APP研发录的同学,先去研究一下此书,对我的帮助还是很大的。传送门:包老师博客地址 源码下载

一 本框架的核心内容就是:用线程池来管理我们的网络请求。不使用Asynctask的原因就是Asynctask不能灵活控制其内部的线程池。Asynctask没有暴露出取消请求的方法。我们使用 ThreadPoolExecutor+Runnable+Handler的原生方式进行网络底层封装。

1 URLData和UrlConfigManager

urlData 是我们自定义的请求实体

/**
     * 接口名
     */
    private String key;
    /**
     * 数据缓存时间
     */
    private long expires;
    /**
     * 请求方式 get或者post
     */
    private String netType;
    /**
     * 请求地址
     */
    private String url;

urlConfigManager是将关于接口的xml配置文件 转换成urldata放入ArrayList中 xml文件如下

<Node
        Expires="300"
        Key="getWeatherInfo"
        NetType="get"
        Url="http://www.weather.com.cn/data/sk/101010100.html" />

2 RemoteService和RequestCallback,RequestParameter。RequestManager,DefaultThreadPool

 RequestCallback callback = new RequestCallback() {
            @Override
            public void onSuccess(String content) {
                Log.i("content", content);
            }

            @Override
            public void onFail(String errorMessage) {
                Log.i("error", errorMessage);
            }

            @Override
            public void onCookieExpired() {

            }
        };
        ArrayList parameters = new ArrayList<>();
        RequestParameter parameter1 = new RequestParameter("k1", "v1");
        RequestParameter parameter2 = new RequestParameter("k1", "v1");
        parameters.add(parameter1);
        parameters.add(parameter2);
        RemoteService.getInstance().invoke(this, "serverDemo", parameters, callback);

a RequestCallback是回调,有onSuccess和onFail两个方法。

b RequestParameter是用来传递调用接口所需要参数键值对的,当然你也可以使用HashMap

c RemoteService这个单例是用来发起请求的,它会创建一个request并将它添加到requestManager中 然后放到DefaultThreadPool的一个线程中去执行这个request。

d requestManager这个集合类是用于取消请求(cancelRequest)的,因为每发起一个请求,都会添加到RequestManager中,所以RequestManager保存了全部Request ,所以在从ActivityA 跳转到ActivityB,为了不产生阻塞,所以要取消ActivityA中所有未完成的Request 。

 * 取消网络请求
 */
public void cancelRequest() {
    if ((requestList != null) && (requestList.size() > 0)) {
        for (final OkHttpRequest request : requestList) {
            if (request.getCall() != null) {
                try {
                    request.getCall().cancel();
                    requestList.remove(request);
                } catch (final UnsupportedOperationException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}`

我们在BaseAcitivty中,会保持对RequestManager一个引用,这样在onDestroy和onPause的时候执行cancelRequest方法取消所有未完成的请求。

e DefaultThreadPool只是对ThreadPoolExecutor和ArrayBlockingQueue的简单封装。我们可以认为它就是一个线程池,每发起一个请求,就由线程池分配一个新的线程来执行该请求。

3 OkHttpRequest 这个类 就是我自己写的代替了以前的HttpClient 。在这个类中,整体的架构设计没有改变。它实现了Runable接口,提供一个run方法来执行请求。

a 第一步 还是根据urlConfigManager得到的urlData来区分get还是post来建立一个request请求。

b 第二步 设置请求超时时间,读写时间,添加cookie到请求头中,添加必要头部信息到请求头中。


            okBuilder.connectTimeout(4000, TimeUnit.MILLISECONDS)
                    .readTimeout(4000, TimeUnit.MILLISECONDS)
                    .writeTimeout(4000, TimeUnit.MILLISECONDS);

            addCookie();// 添加Cookie到请求头中

            setHttpHeaders(okBuilder); //添加必要的头部信息

            mOkHttpClient = okBuilder.build();

c 发起请求,使用requestCallback 处理返回结果。

 //发送请求
            call = mOkHttpClient.newCall(request);
            //结果回调
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, final IOException e) {
                    if (requestCallback != null) {

                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                requestCallback.onFail(e.getMessage());
                            }
                        });
                    } else {
                        // TODO: 2016/11/24  处理接口为空的情况
                    }

                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (requestCallback != null) {
                        int code = response.code();
                        if (code >= 200 && code < 300) {  //代表成功

//                            updateDeltaBetweenServerAndClientTime(response);  // 更新服务器时间和本地时间的差值

                            //okHttp3 如果在头部中 添加了 gzip字段 会自动进行 gzip 解压 这里不在处理
                            String string = response.body().string();
                            Log.i("DataResponse", string);

                            final DataResponse dataResponse = JSON.parseObject(string, DataResponse.class);

                            if (dataResponse.hasError()) {  // 包含错误

                                if (dataResponse.getErrorType() == 1) {
                                    handler.post(new Runnable() {
                                        @Override
                                        public void run() {
                                            requestCallback.onCookieExpired();
                                        }
                                    });
                                } else {
                                    handleNetworkError(dataResponse.getErrorMessage());
                                }

                            } else {
                                //当是get请求 并且缓存时间>0时 保存到缓存
                                if (urlData.getNetType().equals(REQUEST_GET) && urlData.getExpires() > 0) {
                                    CacheManager.getInstance().putFileCache(newUrl, dataResponse.getResult(), urlData.getExpires());
                                }

                                handler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        requestCallback.onSuccess(dataResponse.getResult() + "  success");
                                    }
                                });
                            }
                        } else {
                            handleNetworkError("网络异常2");
                        }

                    } else {
                        // TODO: 2016/11/24  处理接口为空的情况

                    }
                }
            });

d 在本类中,还介绍了关于 cookie的持久化处理,这里不做赘述。

/**
     * 从本地获取cookie列表
     *
     * @return
     */
    public void addCookie() {
        okBuilder.cookieJar(new CookiesManager());
    }

/**
     * 自动管理Cookies
     */
    private class CookiesManager implements CookieJar {
        private final PersistentCookieStore cookieStore = new PersistentCookieStore(activity);

        @Override
        public void saveFromResponse(HttpUrl url, List cookies) {
            if (cookies != null && cookies.size() > 0) {
                for (Cookie item : cookies) {
                    cookieStore.add(url, item);
                }
            }
        }

        @Override
        public List loadForRequest(HttpUrl url) {
            List cookies = cookieStore.get(url);
            return cookies;
        }
    }

二 总结:其实,本次封装就是使用okhttp代替了HttpClient,整体框架还是包老师的架子。具体的okHttp的使用方法和其他思路的封装,请参考鸿杨大神的博客 了解okHttp okHttp封装 本博客源码下载地址 源码下载地址

你可能感兴趣的:(Android—网络请求框架)