Volley 소스 분석 (1) RequestQueue 분석

10841 단어

Volley 소스 분석


2017년에volley는 점차적으로 도태되는 틀이지만 코드가 짧고 정교하며 네트워크 구조 설계가 교묘하여 배울 점이 많다.첫 번째 글은 요청 대기열의 코드를 분석했는데 요청 대기열도 우리가 Volley를 사용하는 관건적인 단계이다.두 번째 글은 디스패치를 분석할 거예요.

RequestQueue


RequestQueue 객체를 만드는 방법은 다음과 같습니다.
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());

대기열은 Http 요청을 시작하는 데 사용됩니다.주로 newRequestQueue 방법을 보는데 이 방법의 핵심 실현은 2개의 매개 변수의 방법이다
newRequestQueue(Context context, HttpStack stack)

이 방법은 다음과 같습니다.
  • CacheDir 디렉토리 만들기
  • userAgent를 만듭니다. 기본값은volly/0이고 실제 패키지 이름 + 버전 코드입니다.예외가 발생하면 userAgent가 기본값
  • 입니다.
  • Stack 초기화, 안드로이드 2.3은 단번에 HttpClientStack으로 대상을 만들고 HttpClientStack은 HttpClient로 이루어진다.안드로이드 2.3이상이면 HurlStack을 사용하여 객체를 만듭니다.뒤에서 우리는 이런 종류의 작용을 분석하고 있다.
  • 만들어진 Stack으로 NetWork 대상을 초기화한다. 즉, Network network = new BasicNetwork(stack); 만들어진 CacheDir로 DiskBasedCache 대상을 초기화하여 RequestQueue 대상의 초기화를 완성한다RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
  • queue 대상의 start 방법을 호출합니다.

  • 다음은 HttpStack의 역할과DiskBasedCache와 NetWork의 역할, 마지막으로 start 방법이 무엇을 했는지 살펴보겠습니다.
    HttpStack은 하나의 인터페이스로 이 인터페이스는 두 개의 실현 클래스만 있는데 하나는 HttpClientStack이고 다른 하나는 HulStack이다.우리는 먼저 구체적인 실현류를 보지 않고 인터페이스 방법의 성명만 본다.
     HttpResponse performRequest(Request> request, Map additionalHeaders)
            throws IOException, AuthFailureError;
    

    이 방법의 역할은 진정으로 인터넷 요청을 하는 데 쓰인다. 구체적으로 그런 http 실현 클래스로 요청을 하면 HttpClient와 HttpUrl로 나뉜다.
    NetWork 인터페이스를 보면 이 인터페이스는 하나의 실현 클래스만 있고 BasicNetWork는 구체적인 실현 클래스를 보지 않고 인터페이스의 방법만 보면 다음과 같다.
    NetworkResponse performRequest(Request> request) throws VolleyError;
    

    이 메서드는 지정된 Request를 실행하는 방법에 대해 설명합니다.
    마지막으로 DiskBasedCache의 기능을 살펴보겠습니다.이 클래스는 Cache의 구체적인 실현 클래스로 캐시된 파일로 하드디스크에 존재하며 기본 하드디스크 크기는 5M이다.위의 몇 개의 인터페이스 기능은 모두 끝났고, 실제 클래스의 대상을 통해 최종적으로 RequestQueue를 구성했다.다음은 구조기 방법의 집행을 살펴보자.

    RequestQueue의 구성원 변수 및 방법


    먼저 RequestQueue의 구성원 변수에 대해 살펴보겠습니다.
  • mSequenceGenerator 이 유형은 AtomicInteger인데 그 기능은 요청한 개수를 통계하고 원자류의 성형을 채택하는 것이다.
  • mWaitingRequests 이 유형은HashMap으로 그 기능은 Request를 저장하고 키는 cachekey이다.저장된quest는 중복된request입니다.
  • mCurrent Requests 이 유형은HashSet입니다. 이 기능은 Request를 저장하는 것입니다. 이 Request를 넣을 수 있는 조건은 현재 파견되거나 기다리고 있는 것입니다.
  • mCacheQueue 이 유형은PriorityBlockingQueue이고 그 기능은 캐시를 저장하는 대기열이다.
  • mNetworkQueue 이 유형은PriorityBlockingQueue이며, 그 기능은 작업 중인 대기열
  • 이다.
  • DEFAULT_NETWORK_THREAD_POOL_SIZE 기본 디스패치의 스레드 초기 값은 4
  • 입니다.
  • mCache 이 유형은Cache 기능으로 응답 메시지를 저장하는 대상response
  • mNetWork 이 유형의 NetWork 기능은 네트워크 요청을 수행하는 것입니다.
  • mDelivery 이 유형은ResponseDelivery이고 그 기능은response
  • 를 분배하는 것이다.
  • mDispatchers 이 유형은 NetworkDispatcher[]이고 그 기능은 NetWork 분배기
  • 이다.
  • mCacheDispatcher 이 유형은CacheDispatcher[]이고 그 기능은 Cache분배기
  • 이다
    다음은 구조 방법을 살펴보겠습니다.
      public RequestQueue(Cache cache, Network network, int threadPoolSize,
                ResponseDelivery delivery) {
            mCache = cache;
            mNetwork = network;
            mDispatchers = new NetworkDispatcher[threadPoolSize];
            mDelivery = delivery;
        }
    

    몇 개의 매개 변수의 구조 방법을 막론하고 최종적으로 이것을 집행할 것이다.위쪽new RequestQueue에서 우리가 전송하는 구조 방법은 Cache와 NetWork 대상밖에 없다. 그러면threadPoolsize는 기본적으로 4이고delivery는new ExecutorDelivery(new Handler(Looper.getMainLooper()))이ExecutorDelivery에 대해 뒤에서 분석한다.
    다음은 RequestQueue의 주요 접근 방식을 살펴보겠습니다.
  • start
  • stop
  • cancel
  • finsh
  • add

  • stop 방법

        public void stop() {
            if (mCacheDispatcher != null) {
                mCacheDispatcher.quit();
            }
            for (final NetworkDispatcher mDispatcher : mDispatchers) {
                if (mDispatcher != null) {
                    mDispatcher.quit();
                }
            }
        }
    

    stop 방법의 모든 코드는 매우 적습니다. 주로 하는 일은 다음과 같습니다.
  • CacheDispatcher가 비어 있지 않으면quit 방법으로 그를 종료합니다.
  • NetWork Dispatcher가 비어 있지 않으면quit 방법으로 로그아웃합니다.

  • 관건은 퀴즈 방법에 있다.
    quit 메서드의 코드는 다음과 같습니다.
        public void quit() {
            mQuit = true;
            interrupt();
        }
    

    CacheDispatcher는 상속 및 Thread입니다.quit 방법의 역할은 종료된 로고 위치를 설정하고interrupt 방법을 호출하는 것입니다.run 방법이 실행되는 과정에서 라인이 중단되어catch 문장 블록의 내용을 실행하고 로고 위치를 검사하며 직접return을 실행합니다.
    다음은 자신의 기능과 관련된 코드를 제거한 후 남은 부분이다.아주 표준적인 라인 퇴출 기법임을 알 수 있다.
    public void run() {
            //        ,   
            while (true) {
                try {
                     //      ,   
                } catch (InterruptedException e) {
                    // We may have been interrupted because it was time to quit.
                    if (mQuit) {
                        return;
                    }
                }
            }
        }
    

    stop 방법 분석 완료

    start 방법

        public void start() {
            stop();  // Make sure any currently running dispatchers are stopped.
            // Create the cache dispatcher and start it.
            mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
            mCacheDispatcher.start();
    
            // Create network dispatchers (and corresponding threads) up to the pool size.
            for (int i = 0; i < mDispatchers.length; i++) {
                NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                        mCache, mDelivery);
                mDispatchers[i] = networkDispatcher;
                networkDispatcher.start();
            }
        }
    

    start 방법이 비교적 간결하기 때문에 나는 여기에 모든 방법의 원본 코드를 내보낸다.start 방법은 주로 다음과 같은 몇 가지를 했다.
  • stop 방법을 호출하여 실행 중인 디스패치를 정지시켰습니다.
  • CacheDispatcher를 만들고 시작합니다.
  • 초기화된 스레드 수에 따라 NetworkDispatcher를 만들고 시작합니다.

  • stop 방법은 위에서 분석한 바와 같이 더 이상 말하지 않겠습니다. stop을 먼저 호출하는 목적은 이미 시작된 디스패치를 먼저 멈추는 것입니다.
    CacheDispather, NetWork Dispatcher를 만듭니다. 그들은 사실 하나의 라인입니다. 그들의 start 방법을 호출합니다.그들의 분석에 관해서는 뒤에 구체적으로 소개한다.

    cancel 방법


    cancel 방법은 실제로는 cancalAll 방법이지만, 실제로는 최종적으로 cancelAll (RequestFilter Filter) 필터를 호출합니다. 실제로는 취소할 Request를 필터합니다.그리고 Request를 호출합니다.cancel. 리퀘스트 클래스에 대한 분석을 뒤에 두십시오.

    finish 방법

    
     void finish(Request request) {
            // Remove from the set of requests currently being processed.
            synchronized (mCurrentRequests) {
                mCurrentRequests.remove(request);
            }
            synchronized (mFinishedListeners) {
              for (RequestFinishedListener listener : mFinishedListeners) {
                listener.onRequestFinished(request);
              }
            }
    
            if (request.shouldCache()) {
                synchronized (mWaitingRequests) {
                    String cacheKey = request.getCacheKey();
                    Queue> waitingRequests = mWaitingRequests.remove(cacheKey);
                    if (waitingRequests != null) {
                        if (VolleyLog.DEBUG) {
                            VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.",
                                    waitingRequests.size(), cacheKey);
                        }
                        // Process all queued up requests. They won't be considered as in flight, but
                        // that's not a problem as the cache has been primed by 'request'.
                        mCacheQueue.addAll(waitingRequests);
                    }
                }
            }
        }
    

    finish 방법은 일반적인 방법으로 이finish 방법은 다음과 같은 몇 가지 일을 집행했다.
  • CurrentRequest에서 이 Request를 제거합니다.
  • finishListener
  • 호출
  • 이 리퀘스트에 캐시가 필요한지 판단하고 캐시가 필요한 리퀘스트에 대해CacheQueue에 다른 것을 넣습니다.

  • 위의 구성원 변수 설명에서currentRequst는 실제적으로 파견되거나 실행 중인 Request를 저장하고finish는 당연히 이 대기열에서 제거합니다.
         /** Callback interface for completed requests. */
        public interface RequestFinishedListener {
            /** Called when a request has finished processing. */
            void onRequestFinished(Request request);
        }
    

    이 인터페이스의 목적은 리퀘스트가 끝난 후에 리셋하는 인터페이스를 제공하는 것이다.
    리퀘스트에 캐시가 필요한지 판단하려면 set Should Cache 설정을 통해 mWaiting Reuqests에서 키에 대응하는 대기열을 제거하고cacheQueue에 대기열을 추가할 수 있습니다.즉, waitingQueue에 같은 Request가 존재한다면 모두 제거합니다.

    add 방법


    add 방법은 리퀘스트를 추가하는 방법입니다. 모든 코드는 다음과 같습니다.
         public  Request add(Request request) {
            // Tag the request as belonging to this queue and add it to the set of current requests.
            request.setRequestQueue(this);
            synchronized (mCurrentRequests) {
                mCurrentRequests.add(request);
            }
    
            // Process requests in the order they are added.
            request.setSequence(getSequenceNumber());
            request.addMarker("add-to-queue");
    
            // If the request is uncacheable, skip the cache queue and go straight to the network.
            if (!request.shouldCache()) {
                mNetworkQueue.add(request);
                return request;
            }
    
            // Insert request into stage if there's already a request with the same cache key in flight.
            synchronized (mWaitingRequests) {
                String cacheKey = request.getCacheKey();
                if (mWaitingRequests.containsKey(cacheKey)) {
                    // There is already a request in flight. Queue up.
                    Queue> stagedRequests = mWaitingRequests.get(cacheKey);
                    if (stagedRequests == null) {
                        stagedRequests = new LinkedList>();
                    }
                    stagedRequests.add(request);
                    mWaitingRequests.put(cacheKey, stagedRequests);
                    if (VolleyLog.DEBUG) {
                        VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                    }
                } else {
                    // Insert 'null' queue for this cacheKey, indicating there is now a request in
                    // flight.
                    mWaitingRequests.put(cacheKey, null);
                    mCacheQueue.add(request);
                }
                return request;
            }
        }
    

    현재 RequestQueue에 Request를 연결하고 mCurrentRequeue에 이 Request를 추가합니다. Request는 대기열에 가입하는 순서를 설정하여 이 Request에 캐시가 필요한지 판단합니다. 캐시가 필요하지 않으면 넷워크Queue에 직접 가입하여 실행되기를 기다립니다.캐시가 필요하면, 이 Waiting Request에 이 Request가 있는지 판단하고, 있으면 이cacheKey에 대응하는 대기열을 얻고, 이 Request를 추가하고, 없으면 Staged Requests를 만들어서 추가합니다.그런 다음 StagedRequests를 WaitingRequest에 넣습니다.cacheKey가 없으면waitingRequest는cacheKey,value는null의 값을 삽입하고,cacheQueue에 Request를 추가합니다.
    이로써 RequestQueue 부분은 분석이 끝났습니다. 그 주요 기능은 전송된 Request에 따라 이 Request를 그 Queue에 추가하고 Dispatcher를 통해 스케줄링하는 것입니다.

    좋은 웹페이지 즐겨찾기