NoHttp源码 初解析 ~

用了那么久的NoHttp这么强大的网络库,但是对里面的源码都是一知半解,只会去怎么去使用,但不了解这个流程是怎样的,俗话说的好,“授人以鱼 不如授如以渔”~单单就会使用,怎么能称的上是合格的程序猿,向着大神看起,学习他们的思想设计~
本人还是名小白,本文还有欠缺考虑的地方请见谅
如果不知道NoHttp的话,
请看严振杰的博客 http://blog.csdn.net/yanzhenjie1003
请看NoHttp github 链接:https://github.com/yanzhenjie/NoHttp

———————我是一条分割线———————–
先看下作者说的源码核心流程是怎样的
这是异步请求 也是大部分应用都是调用这个 版本号1.0.0
异步请求
异步
那我们就遵循上面流程 一步步看 作者是如何做到的
NoHttp.init(application) 这个初始化 就不用说了 传入上下文 和设置 默认的 CookieManger
当面我们每次构建 request对象 需要 传入到 RequestQueue 请求的线程池中,建议这里写成单例~

  public static RequestQueue newRequestQueue(Cache<CacheEntity> cache, int threadPoolSize) {
        return newRequestQueue(HttpRestConnection.getInstance(cache), threadPoolSize);
    }
     public static RequestQueue newRequestQueue(ImplRestConnection implRestConnection, int threadPoolSize) {
        return newRequestQueue(HttpRestParser.getInstance(implRestConnection), threadPoolSize);
    }
     public static RequestQueue newRequestQueue(ImplRestParser implRestParser, int threadPoolSize) {
        RequestQueue requestQueue = new RequestQueue(implRestParser, threadPoolSize);
        requestQueue.start();
        return requestQueue;
    }

上面一步步的单例的形式 都是为了 后面做铺垫的,下文 有解析~
这里构造的方法最终都是到达 newRequestQueue(ImplRestParser implRestParser, int threadPoolSize)
开启 线程池 requestQueue.start();

public void start() {
        stop();
        for (int i = 0; i < mDispatchers.length; i++) {
            RequestDispatcher networkDispatcher = new RequestDispatcher(mUnFinishQueue, mRequestQueue, mImplRestParser);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }

这里就是创建一个 RequestDispatcher 子线程 去轮训这个线程池,mImplRestParser这个 相应解析者同时子线程里,作者说这里面是真正的请求网络的线程咯。
那我们就仔细深入看看着个类里 是怎么做到的

public class RequestDispatcher extends Thread


@Override
    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        while (!mQuit) {
            final Request<?> request;
            try {
                request = mRequestQueue.take();
            } catch (InterruptedException e) {
                if (!mQuit)
                    return;
                continue;
            }

            if (request.isCanceled()) {
                Logger.d(request.url() + " is canceled.");
                continue;
            }

            final int what = request.what();
            final OnResponseListener<?> responseListener = request.responseListener();

            request.start();
            // start
            final ThreadPoster startThread = new ThreadPoster(what, responseListener);
            startThread.onStart();
            PosterHandler.getInstance().post(startThread);

            // request
            Response<?> response = mImplRestParser.parserRequest(request);

            // remove it from queue
            mUnFinishQueue.remove(request);

            // finish
            final ThreadPoster finishThread = new ThreadPoster(what, responseListener);
            finishThread.onFinished();
            PosterHandler.getInstance().post(finishThread);
            request.finish();

            // response
            if (request.isCanceled())
                Logger.d(request.url() + " finish, but it's canceled.");
            else {
                final ThreadPoster responseThread = new ThreadPoster(what, responseListener);
                responseThread.onResponse(response);
                PosterHandler.getInstance().post(responseThread);
            }
        }
    }

RequestDispatcher 其实就是一个线程,不断的从RequestQueue请求队列中take(),如果为空 也不阻塞主线程 因为这是在子线程里操作的~并且 未请求的消息 如果被取消 也会同时取消掉,不会发起请求的~
这个responseListener接口 回调里记录发起请求 开始 结束等状态,最后在未完成的线程池中 移除请求
mUnFinishQueue.remove(request);最终handler发送回主线程上 返回服务器请求结果。

  // 用IRestParser发送请求,并解析结果,这就是上文中说过的。
 Response<?> response = mIRestParser.parserRequest(request);

IRestParser这个响应解析类是 很关键 还没到达网络请求 连接的部分,这个只是个接口,它的实现类 按Ctrl+T可以看到它的实现类,RestParser这个类是它的实现类,通过之前的构造获取到IRestParser的实例

public static RequestQueue newRequestQueue(IRestProtocol iRestProtocol, int threadPoolSize) {
    return newRequestQueue(RestParser.getInstance(iRestProtocol), threadPoolSize);
}

这里可以理解为Nohttp的同步请求开始

// 调用Http协议处理器IRestProtocol分析Request并完成网络请求拿到Response结果。
 mIRestProtocol.requestNetwork(request);

同样类似IRestParser,IRestProtocol也只是一个接口,它的实现类是RestProtocol这个类,这里会根据Nohttp的缓存模式 来进行请求,具体还是看下demo.
这个类中 RestProtocol的
getHttpResponse(request);
这是作者说的 那我们就在看下吧~核心中的核心咯

/**
 * 真正的请求网络。
 */
private ProtocolResult getHttpResponse(IProtocolRequest request) {
    byte[] responseBody = null;
    Connection connection = iRestConnection.getConnection(request); // 从IRestConnection拿到网络连接和响应内容。

    Headers responseHeaders = connection.responseHeaders();
    Exception exception = connection.exception();
    if (exception == null) {
        // 判断是否有响应内容,比如304响应码就没有body。
        if (hasResponseBody(request.getRequestMethod(), responseHeaders.getResponseCode()))
            try {
                // 把服务器响应body转为ByteArray。
                responseBody = IOUtils.toByteArray(connection.serverStream());
            } catch (IOException e) {// IOException.
                exception = e;
            }
    }
    IOUtils.closeQuietly(connection); // 关闭服务器流。
    // 返回响应内容。
    return new ProtocolResult(responseHeaders, responseBody, exception != null, exception);
}

Connection 这个接口类就实现了

public interface Connection extends Closeable {
    /**
     * 拿到URL对象。
     */
    URL getURL();

    /**
     * 拿到相应头。
     */
    Headers responseHeaders();

    /**
     * 拿到服务器的输出流。
     */
    InputStream serverStream();

    /**
     * 拿到请求过程中的异常。
     */
    Exception exception();
}

只要实现上述的方法 就可以替换成底层的类,Okhtttp也可以和Nohttp 具体看详细链接吧~
传送门在此 http://blog.csdn.net/yanzhenjie1003/article/details/52413226

在其中 HttpRestParser 和 HttpRestConnection 这里 应该是请求的过程核心之一,根据request 的缓存模式来进行网络请求,可以看得出来 底层是HttpURLConnection 和 OKHttp一样

 protected Connection getConnection(BasicServerRequest request) {
        Logger.d("--------------Request start--------------");
        Headers responseHeaders = new HttpHeaders();
        InputStream inputStream = null;
        Exception exception = null;
        HttpURLConnection urlConnection = null;
        String url = request.url();
        try {
            if (!NetUtil.isNetworkAvailable())
                throw new NetworkError("The network is not available, please check the network. The requested url is: " + url);

            // MalformedURLException, IOException, ProtocolException, UnknownHostException, SocketTimeoutException
            urlConnection = createHttpURLConnection(request);
            Logger.d("-------Response start-------");
            int responseCode = urlConnection.getResponseCode();
            responseHeaders = parseResponseHeaders(new URI(request.url()), responseCode, urlConnection.getResponseMessage(), urlConnection.getHeaderFields());

            // handle body
            if (responseCode == 301 || responseCode == 302 || responseCode == 303 || responseCode == 307) {
                Connection redirectConnectiont = handleRedirect(request, responseHeaders);
                responseHeaders = redirectConnectiont.responseHeaders();
                inputStream = redirectConnectiont.serverStream();
                exception = redirectConnectiont.exception();
            } else if (hasResponseBody(request.getRequestMethod(), responseCode)) {
                inputStream = getServerStream(responseCode, responseHeaders.getContentEncoding(), urlConnection);
            }
            Logger.d("-------Response end-------");
        } catch (MalformedURLException e) {
            exception = new URLError("The url is malformed: " + url + ".");
        } catch (UnknownHostException e) {
            exception = new UnKnownHostError("Hostname can not be resolved: " + url + ".");
        } catch (SocketTimeoutException e) {
            exception = new TimeoutError("Request time out: " + url + ".");
        } catch (Exception e) {
            exception = e;
        } finally {
            if (exception != null)
                Logger.e(exception);
        }
        Logger.d("--------------Request finish--------------");
        return new Connection(urlConnection, responseHeaders, inputStream, exception);
    }

看了一圈下来 最主要看到那个几个核心处理的类,要好好理解 为啥 这样分层次,如何解耦~ 我要好好膜拜作者去了~~~吃瓜群众路过~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
NoHttp 是专门做Android网络请求与下载的框架。支持HTTP/HTTPS,自动维持Cookie,异步/同步请求,大文件/多文件上传,文件下载;支持304缓存,302/303重定向,支持代理服务器。NoHttp特性:支持HTTP/HTTPS,自动维持Cookie,异步/同步请求,大文件/多文件上传,文件下载,上传下载均有进度。支持304缓存,自定义缓存,302/303重定向,支持代理服务器访问地址(如: Google)。NoHttp是队列,自动为请求排队,可以取消指定请求, 可以取消队列所有请求,亦可以停止队列。支持请求String、Bitmap、Json、JavaBean,可自定义扩展请求类型。Request对象包涵参数、文件、请求头等;Response对象包涵响应内容,响应头等信息,Cookie。使用Gradle构建时添加依赖:// 引用最新版 compile 'com.yolanda.nohttp:nohttp: ' // 或则引用指定版本 compile 'com.yolanda.nohttp:nohttp:1.0.0'一. 请求1.请求String数据// 请求对象 Request request = NoHttp.createStringRequest(url, requestMethod); //添加请求头 request.addHeader("AppVersioin", "2.0"); // 添加请求参数 request.add("userName", "yolanda"); //上传文件 request.add("file", new FileBinary(file)); ...2.请求Json数据// JsonObject Request request = NoHttp.createJsonObjectRequest(url, reqeustMethod); queue.add(what, request, responseListener); … // JsonArray Request request = NoHttp.createJsonArrayRequest(url, reqeustMethod); queue.add(what, request, responseListener);3. 请求Bitmap数据Request request = NoHttp.createImageRequest(url, requestMethod); ...4. 取消请求取消单个请求Request request = NoHttp.createStringRequest(url); ... request.cancel();从队列中取消指定的请求Request request = NoHttp.createStringRequest(url); request.setCancelSign(sign); … queue.cancelBySign(sign);取消队列中所有请求queue.cancelAll();停止队列RequestQueue queue = NoHttp.newRequestQueue(); ... queue.stop();5. 同步请求// 在当前线程发起请求,在线程这么使用 Request request = NoHttp.createStringRequest(url); Response response = NoHttp.startRequestSync(request); if (response.isSucceed()) {     // 请求成功 } else {     // 请求失败 }二. 缓存1. Http标准协议的缓存,比如响应码是304时现在很多公司使用了RESTFUL风格来写Http API,所以这个是必须有的。Request request = NoHttp.createJsonObjectRequest(url); // NoHttp本身是RESTFUL风格的标准Http协议,所以这里不用设置或者设置为DEFAULT request.setCacheMode(CacheMode.DEFAULT); ...2. 当请求服务器失败的时候,读取缓存Request request = NoHttp.createJsonObjectRequest(url); // 非标准Http协议,改变缓存模式为REQUEST_FAILED_READ_CACHE request.setCacheMode(CacheMode.REQUEST_FAILED_READ_CACHE); ...3. 如果发现有缓存直接成功,没有缓存才请求服务器我们知道ImageLoader的核心除了内存优化外,剩下一个就是发现把内地有图片则直接使用,没有则请求服务器,所以NoHttp这一点非常使用做一个ImageLoader。Request request = NoHttp.createJsonObjectRequest(url); // 非标准Http协议,改变缓存模式为IF_NONE_CACHE_REQUEST request.setCacheMode(CacheMode.IF_NONE_CACHE_REQUEST); ...请求图片,缓存图片。// 如果没有缓存才去请求服务器,否则使用缓存,缓存图片演示 Request request = NoHttp.createImageRequest(imageUrl); request.setCacheMode(CacheMode.IF_NONE_CACHE_REQUEST); ...4. 仅仅读取缓存Request request = NoHttp.createJsonObjectRequest(url); // 非标准Http协议,改变缓存模式为ONLY_READ_CACHE request.setCacheMode(CacheMode.ONLY_READ_CACHE); ...注意:缓存不管是String、Json、图片还是任何请求都可以被NoHttp缓存二、响应OnResponseListener responseListener = new OnResponseListener() {     @Override     public void onStart(int what) {         // 请求开始时,可以显示一个Dialog     }     @Override     public void onFinish(int what) {         // 请求接受时,关闭Dialog     }     @Override     public void onSucceed(int what, Response response) {         // 接受请求结果         String result = response.get();         // Bitmap imageHead = response.get(); // 如果是bitmap类型,都是同样的用法     }     @Override     public void onFailed(int what, String url, Object tag, Exception exception, ...) {         // 请求失败或者发生异常         // 这里根据exception处理不同的错误,比如超时、网络不好等     } };三. 自定义请求类型: FastJsonRequest1.定义请求对象public class FastJsonRequest extends RestRequestor { public FastJsonRequest(String url) {     super(url); } public FastJsonRequest(String url, RequestMethod requestMethod) {     super(url, requestMethod); } @Override public JSONObject parseResponse(String url, Headers headers, byte[] responseBody) {     String result = StringRequest.parseResponseString(url, headers, responseBody);     JSONObject jsonObject = null;     if (!TextUtils.isEmpty(result)) {         jsonObject = JSON.parseObject(result);     } else {         // 这里默认的错误可以定义为你们自己的数据格式         jsonObject = JSON.toJSON("{}");     }     return jsonObject; } @Override public String getAccept() {     // 告诉服务器你接受什么类型的数据, 会添加到请求头的Accept中     return "application/json;q=1"; } }2.使用自定义请求-和NoHttp默认请求没有区别Request mRequest = new FastJsonRequest(url, requestMethod); queue.add(what, mRequest, responseListener);五. 下载文件发起下载请求//下载文件 downloadRequest = NoHttp.createDownloadRequest(url, fielDir, fileName, true, false); // what 区分下载 // downloadRequest 下载请求对象 // downloadListener 下载监听 CallServer.getDownloadInstance().add(0, downloadRequest, downloadListener);暂停或者停止下载downloadRequest.cancel();监听下载过程private DownloadListener downloadListener = new DownloadListener() {     @Override     public void onStart(int what, boolean resume, long preLenght, Headers header, long count) {     }     @Override     public void onProgress(int what, int progress, long downCount) {         // 更新下载进度     }     @Override     public void onFinish(int what, String filePath) {     }     @Override     public void onDownloadError(int what, StatusCode code, CharSequence message) {     }     @Override     public void onCancel(int what) {     } }; 标签:NoHttp

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值