Android 프레임 워 크 의 Volley 소스 코드 분석
저 는 가방 에 의존 하 는 형식 으로 여러분 도 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 소스 코드 에 관 한 자 료 는 다른 관련 글 을 주목 하 세 요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.