/// <summary> /// 新增缓存数据 /// </summary> public void Put(string key, Entry entry) { lock (this) { PruneIfNeeded(entry.Data.Length); var file = GetFileForKey(key); try { var fos = file.Open(FileMode.OpenOrCreate); CacheHeader e = new CacheHeader(key, entry); bool success = e.WriteHeader(fos); if (!success) { fos.Close(); VolleyLog.D("Failed to write header for {0}", file.FullName); throw new IOException(); } fos.Write(entry.Data, 0, entry.Data.Length); fos.Close(); PutEntry(key, e); return; } catch (IOException) { } file.Delete(); if (File.Exists(file.FullName)) { VolleyLog.D("Could not clean up file {0}", file.FullName); } } }
public void Finish(String tag) { if (mRequestQueue != null) { mRequestQueue.Finish(this); } if (MarkerLog.ENABLED) { long threadId = Java.Lang.Thread.CurrentThread().Id; if (Looper.MyLooper() != Looper.MainLooper) { Handler mainThread = new Handler(Looper.MainLooper); mainThread.Post(() => { mEventLog.Add(tag, threadId); mEventLog.Finish(this.ToString()); }); return; } mEventLog.Add(tag, threadId); mEventLog.Finish(this.ToString()); } else { long requestTime = SystemClock.ElapsedRealtime() - mRequestBirthTime; if (requestTime >= SLOW_REQUEST_THRESHOLD_MS) { VolleyLog.D("{0} ms:{1}", requestTime, this.ToString()); } } }
/// <summary> /// 输出请求完成的信息(仅限调试) /// </summary> private void LogSlowRequests(long requestLifetime, Request request, byte[] responseContents, HttpStatusCode statusCode) { if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) { VolleyLog.D("HTTP response for request=<{0}> [lifetime={1}],[size={2}], [rc={3}],[retryCount={4}]", requestLifetime, requestLifetime, responseContents != null ? responseContents.Length.ToString() : "null", statusCode, request.GetRetryPolicy().CurrentRetryCount); } }
/// <summary> /// 删除缓存数据 /// </summary> public void Remove(string key) { lock (this) { var fi = GetFileForKey(key); fi.Delete(); RemoveEntry(key); if (File.Exists(fi.FullName)) { VolleyLog.D("Could not delete cache entry for key={0},filename={1}", key, fi.FullName); } } }
public override byte[] GetBody() { try { return(mRequestBody == null ? null : Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(mRequestBody))); } catch (Exception) { VolleyLog.WTF("Unsupported Encoding while trying to get the bytes of {0} using {1}", mRequestBody, PROTOCOL_CHARSET); return(null); } }
public Request Add(Request request) { request.SetRequestQueue(this); //添加到当前请求列表中 lock (mCurrentRequests) { mCurrentRequests.Add(request); } request.Sequence = GetSequenceNumber(); request.AddMarker("add-to-queue"); //如果请求不需要缓存则直接加入到网络请求队列中 if (!request.ShouldCache()) { mNetworkQueue.Enqueue(request); return(request); } /* * 先将请求加入到缓存请求队列中,并且将后面的重复请求 * 添加到mWaitingRequests中,目的是当第一个请求完成后 * 后面重复的请求直接添加到缓存请求队列中,避免重复对 * 网络进行请求 */ lock (mWaitingRequests) { String cacheKey = request.GetCacheKey(); if (mWaitingRequests.ContainsKey(cacheKey)) { Queue <Request> stagedRequests = null; mWaitingRequests.TryGetValue(cacheKey, out stagedRequests); if (stagedRequests == null) { stagedRequests = new Queue <Request>(); } stagedRequests.Enqueue(request); if (VolleyLog.DEBUG) { VolleyLog.V("Request for cacheKey={0} is in flight,putting on hold.", cacheKey); } } else { mWaitingRequests.Add(cacheKey, null); mCacheQueue.Enqueue(request); } return(request); } }
/// <summary> /// 初始化缓存 /// </summary> public void Initialize() { lock (this) { if (!mRootDirectory.Exists) { mRootDirectory.Create(); if (!mRootDirectory.Exists) { VolleyLog.E("Unable to create cache dir {0}", mRootDirectory.FullName); } return; } //获取已缓存文件并添加到缓存表中 FileInfo[] files = mRootDirectory.GetFiles(); if (files == null) { return; } foreach (FileInfo file in files) { FileStream fs = null; try { fs = file.Open(FileMode.OpenOrCreate); CacheHeader entry = CacheHeader.ReadHeader(fs); entry.Size = fs.Length; PutEntry(entry.Key, entry); } catch (IOException) { if (file != null) { file.Delete(); } } finally { try { if (fs != null) { fs.Close(); } } catch (IOException) { } } } } }
public override Response ParseNetworkResponse(NetworkResponse response) { lock (sDecodeLock) { try { return(DoParse(response)); } catch (Java.Lang.OutOfMemoryError e) { VolleyLog.E("Caught OOM for {0} byte image,url={1}", response.Data.Length, Url); return(Response.Error(new ParseError(e))); } } }
/// <summary> /// 清除缓存 /// </summary> public void Clear() { lock (this) { FileInfo[] files = mRootDirectory.GetFiles(); if (files != null) { foreach (FileInfo file in files) { file.Delete(); } } mEntries.Clear(); mTotalSize = 0; VolleyLog.D("Cache cleared."); } }
/// <summary> /// 当需要的空间大于指定空间后清除部分缓存 /// </summary> private void PruneIfNeeded(int neededSpace) { if (mTotalSize + neededSpace < mMaxCacheSizeInBytes) { return; } if (VolleyLog.DEBUG) { VolleyLog.V("Pruning old cache entries."); } long before = mTotalSize; int prunedFiles = 0; long startTime = SystemClock.ElapsedRealtime(); Dictionary <string, CacheHeader> delDic = new Dictionary <string, CacheHeader>(); foreach (KeyValuePair <String, CacheHeader> pair in mEntries) { CacheHeader e = pair.Value; var fi = GetFileForKey(e.Key); fi.Delete(); if (!File.Exists(fi.FullName)) { mTotalSize -= e.Size; } else { VolleyLog.D("Could not delete cache entry for key={0},filename={1}", e.Key, GetFilenameForKey(e.Key)); } prunedFiles++; delDic.Add(pair.Key, pair.Value); if (mTotalSize + neededSpace < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) { break; } } foreach (KeyValuePair <string, CacheHeader> del in delDic) { mEntries.Remove(del.Key); } if (VolleyLog.DEBUG) { VolleyLog.V("Pruned {0} files,{1} bytes,{2} ms", prunedFiles, (mTotalSize - before), SystemClock.ElapsedRealtime() - startTime); } }
public void Finish(Request request) { lock (mCurrentRequests) { mCurrentRequests.Remove(request); } lock (mFinishedListeners) { foreach (IRequestFinishedListener listener in mFinishedListeners) { listener.OnRequestFinished(request); } } if (request.ShouldCache()) { /* * 在该请求完成并缓存后将后面其他重复的 * 请求直接加入到缓存请求队列中 */ lock (mWaitingRequests) { String cacheKey = request.GetCacheKey(); Queue <Request> waitingRequets = null; mWaitingRequests.TryGetValue(cacheKey, out waitingRequets); mWaitingRequests.Remove(cacheKey); if (waitingRequets != null) { if (VolleyLog.DEBUG) { VolleyLog.V("Releasing {0} waiting requests for cacheKey={1}", waitingRequets.Count, cacheKey); } foreach (Request addrequest in waitingRequets) { mCacheQueue.Enqueue(addrequest); } } } } }
/// <summary> /// 将缓存信息写入流中 /// </summary> public bool WriteHeader(Stream output) { try { DiskBasedCache.WriteInt(output, DiskBasedCache.CACHE_MAGIC); DiskBasedCache.WriteString(output, Key); DiskBasedCache.WriteString(output, ETag == null ? "" : ETag); DiskBasedCache.WriteLong(output, ServerDate); DiskBasedCache.WriteLong(output, LastModified); DiskBasedCache.WriteLong(output, Ttl); DiskBasedCache.WriteLong(output, SoftTtl); DiskBasedCache.WriteStringStringMap(ResponseHeaders, output); output.Flush(); return(true); } catch (Exception e) { VolleyLog.D("{0}", e.ToString()); return(false); } }
/// <summary> /// 获取缓存数据 /// </summary> public Entry Get(string key) { lock (this) { CacheHeader entry = null; mEntries.TryGetValue(key, out entry); if (entry == null) { return(null); } FileInfo file = GetFileForKey(key); FileStream fs = null; try { fs = file.Open(FileMode.OpenOrCreate); CacheHeader.ReadHeader(fs); byte[] data = StreamToBytes(fs, (int)(fs.Length - fs.Position)); return(entry.ToCacheEntry(data)); } catch (IOException e) { VolleyLog.D("{0}:{1}", file.FullName, e.ToString()); } finally { if (fs != null) { try { fs.Close(); } catch (IOException) { } } } return(null); } }
protected void LogError(String what, String url, long start) { long now = SystemClock.ElapsedRealtime(); VolleyLog.V("HTTP ERROR({0}) {1} ms to fetch {2}", what, (now - start), url); }
/// <summary> /// 处理请求的核心 /// 不包含底层请求的创建 /// </summary> public NetworkResponse PerformRequest(Request request) { long requestStart = SystemClock.ElapsedRealtime(); while (true) { HttpWebResponse httpResponse = null; byte[] responseContents = null; Dictionary <String, String> responseHeaders = null; try { Dictionary <String, String> headers = new Dictionary <string, string>(); AddCacheHeaders(headers, request.CacheEntry); //处理请求 httpResponse = mHttpStack.PerformRequest(request, headers); var statusCode = httpResponse.StatusCode; responseHeaders = ConvertHeaders(httpResponse.Headers); if (statusCode == HttpStatusCode.MovedPermanently || statusCode == HttpStatusCode.Moved) { String newUrl = responseHeaders["Location"]; request.SetRedirectUrl(newUrl); } //获取请求到的内容 Stream output = httpResponse.GetResponseStream(); if (output != null) { responseContents = EntityToBytes(output); } else { responseContents = new byte[0]; } long requestLifetime = SystemClock.ElapsedRealtime() - requestStart; LogSlowRequests(requestLifetime, request, responseContents, statusCode); if (statusCode < HttpStatusCode.OK || (int)statusCode > 299) { throw new IOException(); } return(new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.ElapsedRealtime() - requestStart)); } catch (WebException ex) { if (ex.Response != null) { var result = ex.Response as HttpWebResponse; if (result.StatusCode == HttpStatusCode.NotModified) { Entry entry = request.CacheEntry; if (entry == null) { return(new NetworkResponse(HttpStatusCode.NotModified, null, responseHeaders, true, SystemClock.ElapsedRealtime() - requestStart)); } //entry.ResponseHeaders = entry.ResponseHeaders.Intersect(responseHeaders).ToDictionary(x => x.Key, x => x.Value); return(new NetworkResponse(HttpStatusCode.NotModified, entry.Data, entry.ResponseHeaders, true, SystemClock.ElapsedRealtime() - requestStart)); } } throw new NetworkError(ex); } catch (TimeoutException) { AttempRetryOnException("connection", request, new TimeoutError()); } catch (IOException e) { HttpStatusCode statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { statusCode = httpResponse.StatusCode; } else { throw new NoConnectionError(e); } if (statusCode == HttpStatusCode.MovedPermanently) { VolleyLog.E("Request at {0} has been redirected to {1}", request.OriginUrl, request.Url); } else { VolleyLog.E("Unexpected response code {0} for {1}", statusCode, request.Url); } if (responseContents != null) { networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.ElapsedRealtime() - requestStart); if (statusCode == HttpStatusCode.Unauthorized || statusCode == HttpStatusCode.Forbidden) { AttempRetryOnException("auth", request, new AuthFailureError()); } else if (statusCode == HttpStatusCode.MovedPermanently || statusCode == HttpStatusCode.Moved) { AttempRetryOnException("redirect", request, new AuthFailureError(networkResponse)); } else { throw new ServerError(networkResponse); } } else { throw new NetworkError(networkResponse); } } } }
public override void Run() { Process.SetThreadPriority(ThreadPriority.Background); while (true) { long startTimeMs = SystemClock.ElapsedRealtime(); Request request; if (!mQueue.TryDequeue(out request)) { if (mQuit) { return; } continue; } try { request.AddMarker("network-queue-take"); if (request.IsCanceled) { request.Finish("network-discard-cancelled"); continue; } AddTrafficStatsTag(request); NetworkResponse networkResponse = mNetwork.PerformRequest(request); request.AddMarker("network-http-complete"); if (networkResponse.NotModified && request.HasHadResponseDelivered()) { request.Finish("not-modified"); continue; } Response response = request.ParseNetworkResponse(networkResponse); request.AddMarker("network-parse-complete"); if (request.ShouldCache() && response.CacheEntry != null) { mCache.Put(request.GetCacheKey(), response.CacheEntry); request.AddMarker("network-cache-written"); } request.MarkDelivered(); mDelivery.PostResponse(request, response); } catch (VolleyError volleyError) { volleyError.NetworkTimeMs = SystemClock.ElapsedRealtime() - startTimeMs; ParseAndDeliverNetworkError(request, volleyError); } catch (Exception e) { VolleyLog.E(e, "Unhandled exception {0}", e.ToString()); VolleyError volleyError = new VolleyError(e); volleyError.NetworkTimeMs = SystemClock.ElapsedRealtime() - startTimeMs; mDelivery.PostError(request, volleyError); } } }
public override void Run() { if (DEBUG) { VolleyLog.V("start new dispatcher"); } Process.SetThreadPriority(ThreadPriority.Background); mCache.Initialize(); while (true) { try { Request request = null; if (!mCacheQueue.TryDequeue(out request)) { if (mQuit) { return; } continue; } request.AddMarker("cache-queue-take"); //请求是否已取消 if (request.IsCanceled) { request.Finish("cache-discard-canceled"); continue; } //不存在该缓存 Entry entry = mCache.Get(request.GetCacheKey()); if (entry == null) { request.AddMarker("cache-miss"); mNetworkQueue.Enqueue(request); continue; } //缓存过期 if (entry.IsExpired) { request.AddMarker("cache-hit-expired"); request.CacheEntry = entry; mNetworkQueue.Enqueue(request); continue; } //缓存命中 request.AddMarker("cache-hit"); Response response = request.ParseNetworkResponse(new NetworkResponse(entry.Data, entry.ResponseHeaders)); request.AddMarker("cache-hit-parsed"); //判断缓存是否需要更新 if (!entry.RefreshNeeded()) { mDelivery.PostResponse(request, response); } else { request.AddMarker("cache-hit-refresh-needed"); request.CacheEntry = entry; response.Intermediate = true; mDelivery.PostResponse(request, response, () => { mNetworkQueue.Enqueue(request); }); } } catch (Exception) { if (mQuit) { return; } continue; } } }