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);
    }

看了一圈下來 最主要看到那個幾個核心處理的類,要好好理解 爲啥 這樣分層次,如何解耦~ 我要好好膜拜作者去了~~~吃瓜羣衆路過~

發佈了32 篇原創文章 · 獲贊 5 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章