Android 프레임 워 크 의 Volley 소스 코드 분석

19995 단어 AndroidVolley
볼 리
저 는 가방 에 의존 하 는 형식 으로 여러분 도 gradle 형식 으로 의존 할 수 있 습 니 다.

자,이제 코드 가 올 라 갑 니 다.

//  volley     
        RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
        StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                Log.d("MainActivity", "----->" + s);

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Log.d("MainActivity", "---volleyError-->" + volleyError);
            }
        });
        requestQueue.add(stringRequest);
코드 를 통 해 알 수 있 듯 이 우선 newRequestQueue 에서 요청 대기 열 을 가 져 온 다음 StringRequest 라 는 요청 을 요청 대기 열 에 추가 하면 됩 니 다.이렇게 간단 합 니 다.물론 요청 은 StringRequest 가 아 닙 니 다.그리고 Json Object Request,ImageRequest 등 이 있 습 니 다.하지만 용법 은 똑 같 습 니 다.여 기 는 코드 를 붙 이지 않 습 니 다.볼 리 의 간단 한 사용 은 이렇게 요청 할 수 있 습 니 다.쉽 지 않 아 요?
볼 리 실행 원리
그러나 이것 은 본 편의 중점 이 아니 라 어떻게 집행 되 는 지 분석 하 는 것 이 중점 이다.먼저 위의 그림.

우 리 는 먼저 new RequestQueue 라 는 내부 가 어떻게 실행 되 는 지 보 겠 습 니 다.코드 는 처음에 몇 가지 리 셋 방법 을 연속 으로 실 행 했 고 마지막 으로 new RequestQueue 로 갔습니다.

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
    File cacheDir = new File(context.getCacheDir(), "volley");
    String userAgent = "volley/0";

    try {
        String packageName = context.getPackageName();
        PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
        userAgent = packageName + "/" + info.versionCode;
    } catch (NameNotFoundException var7) {
        ;
    }

    //             2.3     HTTPClient,2.3      HttpURLConnection
    if (stack == null) {
        if (VERSION.SDK_INT >= 9) {
            stack = new HurlStack();
        } else {
            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
        }
    }

    Network network = new BasicNetwork((HttpStack)stack);
    RequestQueue queue;
    if (maxDiskCacheBytes <= -1) {
        queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
    } else {
        queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
    }

    queue.start();
    return queue;
}
여기 서 우 리 는 한 버 전 판단 을 보 았 습 니 다.순간 적 으로 익숙 한 것 같 지 않 습 니까?맞습니다.앞에서 말 했 듯 이 volley 2.3 전에 HTTPClient 를 사 용 했 고 2.3 후에 HttpURLConnection 을 사 용 했 습 니 다.바로 여기 서 판단 한 것 입 니 다.이어서 quue.start()보기;

public void start() {
        this.stop();
        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
        this.mCacheDispatcher.start();

        for(int i = 0; i < this.mDispatchers.length; ++i) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
            this.mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }

    }
mCacheDispatcher 는 캐 시 스케줄 러 입 니 다.NetworkDispatcher 는 네트워크 스케줄 러 입 니 다.이 this.mdpatcher.length 시스템 의 기본 크기 는 4 입 니 다.즉,여기 서 총 5 개의 스 레 드 가 배경 에서 실 행 됩 니 다.
자,여기까지 하면 됩 니 다.소스 코드 를 보면 모든 줄 을 이해 하지 마 세 요.그렇지 않 으 면 나 올 수 없습니다.여기까지 이 RequestQueue 상 대 를 받 았 습 니 다.앞 에 사 용 된 코드 를 뒤 돌아 보 세 요.

//  volley     
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
    @Override
    public void onResponse(String s) {
        Log.d("MainActivity", "----->" + s);

    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError volleyError) {
        Log.d("MainActivity", "---volleyError-->" + volleyError);
    }
});
requestQueue.add(stringRequest);
우 리 는 이 RequestQueue 대상 을 받 은 후에 이 요청 을 add 방법 으로 대기 열 에 추가 합 니 다.우 리 는 이 add()방법 이 어떻게 실행 되 는 지 봅 시다.

public <T> Request<T> add(Request<T> request) {
        request.setRequestQueue(this);
        Set var2 = this.mCurrentRequests;
        synchronized(this.mCurrentRequests) {
            this.mCurrentRequests.add(request);
        }

        request.setSequence(this.getSequenceNumber());
        request.addMarker("add-to-queue");
        if (!request.shouldCache()) { //      
            this.mNetworkQueue.add(request);
            return request;
        } else {
            Map var7 = this.mWaitingRequests;
            synchronized(this.mWaitingRequests) {
                String cacheKey = request.getCacheKey();
                if (this.mWaitingRequests.containsKey(cacheKey)) { //         ,         
                    Queue<Request<?>> stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);
                    if (stagedRequests == null) {
                        stagedRequests = new LinkedList();
                    }

                    ((Queue)stagedRequests).add(request);
                    this.mWaitingRequests.put(cacheKey, stagedRequests);
                    if (VolleyLog.DEBUG) {
                        VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});
                    }
                } else {
                //              mCacheQueue,    mWaitingRequests                   
                    this.mWaitingRequests.put(cacheKey, (Object)null);
                    this.mCacheQueue.add(request);
                }

                return request;
            }
        }
    }
코드 에서 보 듯 이 캐 시 가능 여 부 를 먼저 판단 할 수 있 습 니 다.물론 기본 값 은 캐 시 가능 합 니 다.캐 시 할 수 없다 면 this.mNetworkQueue.add(request)를 통 해;네트워크 요청 대기 열 에 요청 을 추가 합 니 다.캐 시 할 수 있다 면 이 요청 이 요청 되 었 는 지 여 부 를 판단 할 수 있 습 니 다.실행 되 었 다 면 this.mWaiting Requests.put(cacheKey,staged Requests)를 통 해.mWaiting Requests 대기 열 에 추가 합 니 다.요청 을 반복 하지 않 습 니 다.그렇지 않 으 면 캐 시 대기 열 에 추가 합 니 다.
대체적인 절 차 는 이렇다.이제 캐 시 와 네트워크 가 어떻게 실행 되 는 지 봅 시다.start()방법 을 찾 았 습 니 다.

public void start() {
        this.stop();
        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
        this.mCacheDispatcher.start();

        for(int i = 0; i < this.mDispatchers.length; ++i) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
            this.mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }

    }
CacheDispatcher 를 보고 run()방법 을 찾 습 니 다.

public void run() {
        if (DEBUG) {
            VolleyLog.v("start new dispatcher", new Object[0]);
        }

        Process.setThreadPriority(10);
        this.mCache.initialize();

        while(true) {
            while(true) {
                while(true) {
                    while(true) {
                        try {
                            while(true) {
                                final Request<?> request = (Request)this.mCacheQueue.take(); //             
                                request.addMarker("cache-queue-take");
                                if (request.isCanceled()) { //        ,     ,      finish 
                                    request.finish("cache-discard-canceled");
                                } else {
                                    Entry entry = this.mCache.get(request.getCacheKey());
                                    if (entry == null) {//              ,                
                                        request.addMarker("cache-miss");
                                        this.mNetworkQueue.put(request);
                                    } else if (entry.isExpired()) { //       ,                
                                        request.addMarker("cache-hit-expired");
                                        request.setCacheEntry(entry);
                                        this.mNetworkQueue.put(request);
                                    } else { //         
                                        request.addMarker("cache-hit");
                                        Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
                                        request.addMarker("cache-hit-parsed");
                                        if (entry.refreshNeeded()) {
                                            request.addMarker("cache-hit-refresh-needed");
                                            request.setCacheEntry(entry);
                                            response.intermediate = true;
                                            this.mDelivery.postResponse(request, response, new Runnable() {
                                                public void run() {
                                                    try {
                                                        CacheDispatcher.this.mNetworkQueue.put(request);
                                                    } catch (InterruptedException var2) {
                                                        ;
                                                    }

                                                }
                                            });
                                        } else {
                                            this.mDelivery.postResponse(request, response);
                                        }
                                    }
                                }
                            }
                        } catch (InterruptedException var4) {
                            if (this.mQuit) {
                                return;
                            }
                        }
                    }
                }
            }
        }
    }
여기에 몇 개의 순환 이 새 겨 져 있어 서 좀 어수선 하 네요.하지만 천천히 분석 해 보면 알 수 있 듯 이 분명 합 니 다.나 는 주석 위 에 썼 으 니,여 기 는 중복 하지 않 겠 다.
네트워크 스 레 드 가 어떻게 실행 되 는 지 네트워크 디 스 패 치 를 보고 있 습 니 다.똑 같이 run()방법 을 찾 습 니 다.

public void run() {
        Process.setThreadPriority(10);

        while(true) {
            long startTimeMs;
            Request request;
            while(true) {
                startTimeMs = SystemClock.elapsedRealtime();

                try {
                    request = (Request)this.mQueue.take(); //       
                    break;
                } catch (InterruptedException var6) {
                    if (this.mQuit) {
                        return;
                    }
                }
            }

            try {
                request.addMarker("network-queue-take");
                if (request.isCanceled()) { //       ,    finish 
                    request.finish("network-discard-cancelled");
                } else {//      
                    this.addTrafficStatsTag(request);
                    NetworkResponse networkResponse = this.mNetwork.performRequest(request);
                    request.addMarker("network-http-complete");
                    if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                        request.finish("not-modified");
                    } else {
                        Response<?> response = request.parseNetworkResponse(networkResponse);
                        request.addMarker("network-parse-complete");
                        if (request.shouldCache() && response.cacheEntry != null) {
                            this.mCache.put(request.getCacheKey(), response.cacheEntry);
                            request.addMarker("network-cache-written");
                        }

                        request.markDelivered();
                        this.mDelivery.postResponse(request, response);
                    }
                }
            } catch (VolleyError var7) {
                var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                this.parseAndDeliverNetworkError(request, var7);
            } catch (Exception var8) {
                VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
                VolleyError volleyError = new VolleyError(var8);
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                this.mDelivery.postError(request, volleyError);
            }
        }
    }
코드 가 비교적 많 습 니 다.우 리 는 NetworkResponse network Response=this.mNetwork.performRequest(request)를 직접 찾 습 니 다.이 코드,이 코드 는 네트워크 를 요청 하 는 코드,가장 핵심 적 인 것 입 니 다.performRequest 는 인터페이스 입 니 다.이 performRequest()방법 을 봅 시다.Network 는 버 전 판단 을 처음 말 할 때 코드 Network network=new Basic Network(HttpStack)stack)가 들 어 있 습 니 다.이 코드 에서 우 리 는 Basic Network 가 최종 적 으로 네트워크 요청 을 실현 하 는 클래스 라 는 것 을 알 수 있 습 니 다.performRequest 방법 을 찾 았 습 니 다.

public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();

        while(true) {
            HttpResponse httpResponse = null;
            byte[] responseContents = null;
            Map responseHeaders = Collections.emptyMap();

            try {
                Map<String, String> headers = new HashMap();
                this.addCacheHeaders(headers, request.getCacheEntry());
                httpResponse = this.mHttpStack.performRequest(request, headers);
                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                if (statusCode == 304) {
                    Entry entry = request.getCacheEntry();
                    if (entry == null) {
                        return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                    }

                    entry.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(304, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                }

                if (statusCode == 301 || statusCode == 302) {
                    String newUrl = (String)responseHeaders.get("Location");
                    request.setRedirectUrl(newUrl);
                }

                byte[] responseContents;
                if (httpResponse.getEntity() != null) {
                    responseContents = this.entityToBytes(httpResponse.getEntity());
                } else {
                    responseContents = new byte[0];
                }

                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                this.logSlowRequests(requestLifetime, request, responseContents, statusLine);
                if (statusCode >= 200 && statusCode <= 299) {
                    return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                }

                throw new IOException();
            } catch (SocketTimeoutException var12) {
                attemptRetryOnException("socket", request, new TimeoutError());
            } catch (ConnectTimeoutException var13) {
                attemptRetryOnException("connection", request, new TimeoutError());
            } catch (MalformedURLException var14) {
                throw new RuntimeException("Bad URL " + request.getUrl(), var14);
            } catch (IOException var15) {
                int statusCode = false;
                NetworkResponse networkResponse = null;
                if (httpResponse == null) {
                    throw new NoConnectionError(var15);
                }

                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (statusCode != 301 && statusCode != 302) {
                    VolleyLog.e("Unexpected response code %d for %s", new Object[]{statusCode, request.getUrl()});
                } else {
                    VolleyLog.e("Request at %s has been redirected to %s", new Object[]{request.getOriginUrl(), request.getUrl()});
                }

                if (responseContents == null) {
                    throw new NetworkError(networkResponse);
                }

                networkResponse = new NetworkResponse(statusCode, (byte[])responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                if (statusCode != 401 && statusCode != 403) {
                    if (statusCode != 301 && statusCode != 302) {
                        throw new ServerError(networkResponse);
                    }

                    attemptRetryOnException("redirect", request, new AuthFailureError(networkResponse));
                } else {
                    attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
                }
            }
        }
    }
코드 가 비교적 많 지만 대부분의 코드 는 상태 반환 코드 를 판단 하 는 것 이 므 로 신경 쓸 필요 가 없다.
httpResponse=this.MHttpStack.performRequest(request,headers)를 직접 봅 니 다.이 코드,Http Stack 이거 익숙 하지 않 아 요?없다괜찮아 요.코드 복사 한 번 더 할 게 요.

if (stack == null) {
    if (VERSION.SDK_INT >= 9) {
        stack = new HurlStack();
    } else {
        stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
    }
}
아니면 이 버 전에 서 여 기 를 판단 하 는 것 입 니까?여기 가 바로 HurlStack 이 진정한 네트워크 요청 유형 입 니 다.네트워크 요청 은 바로 이런 종류 에 쓰 여 있 습 니 다.자,볼 리 의 전체 절 차 는 대략 이 렇 습 니 다.지금 모두 고 개 를 돌려 최초의 어떤 그림 을 보 았 는 지 많이 알 고 있 지 않 습 니까?
이상 은 안 드 로 이 드 프레임 워 크 의 Volley 소스 코드 를 분석 하 는 상세 한 내용 입 니 다.안 드 로 이 드 프레임 워 크 의 Volley 소스 코드 에 관 한 자 료 는 다른 관련 글 을 주목 하 세 요!

좋은 웹페이지 즐겨찾기