public void finish(String paramString) { try { this.mFinished = true; long l1 = getTotalDuration(); if (l1 <= 0L) ; while (true) { return; long l2 = ((Marker) this.mMarkers.get(0)).time; Object[] arrayOfObject1 = new Object[2]; arrayOfObject1[0] = Long.valueOf(l1); arrayOfObject1[1] = paramString; VolleyLog.d("(%-4d ms) %s", arrayOfObject1); Iterator localIterator = this.mMarkers.iterator(); while (localIterator.hasNext()) { Marker localMarker = (Marker) localIterator.next(); long l3 = localMarker.time; Object[] arrayOfObject2 = new Object[3]; arrayOfObject2[0] = Long.valueOf(l3 - l2); arrayOfObject2[1] = Long.valueOf(localMarker.thread); arrayOfObject2[2] = localMarker.name; VolleyLog.d("(+%-4d) [%2d] %s", arrayOfObject2); l2 = l3; } } } finally { } }
/** Returns the cache entry with the specified key if it exists, null otherwise. */ @Override public synchronized Entry get(String key) { CacheHeader entry = mEntries.get(key); // 获取摘要 // if the entry does not exist, return. if (entry == null) { return null; } File file = getFileForKey(key); // 获取文件 CountingInputStream cis = null; try { cis = new CountingInputStream(new FileInputStream(file)); CacheHeader.readHeader(cis); // eat header文件的具体内容在摘要之后,所有先读取摘要,将当前读取位置移动到摘要之后 byte[] data = streamToBytes(cis, (int) (file.length() - cis.bytesRead)); // 当前位置移动到摘要之后,读取缓存内容 return entry.toCacheEntry(data); // 根据读取的缓存内容,结合缓存摘要,生成Cache.Entry对象 } catch (IOException e) { VolleyLog.d("%s: %s", file.getAbsolutePath(), e.toString()); remove(key); // 发生异常则删除异常缓存 return null; } finally { if (cis != null) { try { cis.close(); } catch (IOException ioe) { return null; } } } }
/** * Initializes the DiskBasedCache by scanning for all files currently in the specified root * directory. Creates the root directory if necessary. */ @Override public synchronized void initialize() { if (!mRootDirectory.exists()) { // 如果根目录不存在,创建根目录 if (!mRootDirectory.mkdirs()) { VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath()); } return; } File[] files = mRootDirectory.listFiles(); if (files == null) { return; } // 遍历所有的文件,将文件转换为CacheHeader对象,并将其添加到缓存集合之中 for (File file : files) { FileInputStream fis = null; try { fis = new FileInputStream(file); CacheHeader entry = CacheHeader.readHeader(fis); entry.size = file.length(); putEntry(entry.key, entry); } catch (IOException e) { if (file != null) { file.delete(); // 如果存在异常则删除异常文件 } } finally { try { if (fis != null) { fis.close(); } } catch (IOException ignored) { } } } }
/** Reads the contents of HttpEntity into a byte[]. */ private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError { PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength()); byte[] buffer = null; try { InputStream in = entity.getContent(); if (in == null) { throw new ServerError(); } buffer = mPool.getBuf(1024); int count; while ((count = in.read(buffer)) != -1) { bytes.write(buffer, 0, count); } return bytes.toByteArray(); } finally { try { // Close the InputStream and release the resources by "consuming the content". entity.consumeContent(); } catch (IOException e) { // This can happen if there was an exception above that left the entity in // an invalid state. VolleyLog.v("Error occured when calling consumingContent"); } mPool.returnBuf(buffer); bytes.close(); } }
/** * Called from {@link Request#finish(String)}, indicating that processing of the given request has * finished. * * <p>Releases waiting requests for <code>request.getCacheKey()</code> if <code> * request.shouldCache()</code>. * * <p>(1). 首先从正在进行中请求集合mCurrentRequests中移除该请求。 (2). * 然后查找请求等待集合mWaitingRequests中是否存在等待的请求,如果存在,则将等待队列移除, * 并将等待队列所有的请求添加到缓存请求队列中,让缓存请求处理线程CacheDispatcher自动处理。 */ <T> void finish(Request<T> request) { // Remove from the set of requests currently being processed. synchronized (mCurrentRequests) { mCurrentRequests.remove(request); } synchronized (mFinishedListeners) { for (RequestFinishedListener<T> listener : mFinishedListeners) { listener.onRequestFinished(request); } } if (request.shouldCache()) { synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); Queue<Request<?>> 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); } } } }
/** * Notifies the request queue that this request has finished (successfully or with error). * * <p>Also dumps all events from this request's event log; for debugging. */ void finish(final String tag) { if (mRequestQueue != null) { mRequestQueue.finish(this); } if (MarkerLog.ENABLED) { final long threadId = Thread.currentThread().getId(); if (Looper.myLooper() != Looper.getMainLooper()) { // If we finish marking off of the main thread, we need to // actually do it on the main thread to ensure correct ordering. Handler mainThread = new Handler(Looper.getMainLooper()); mainThread.post( new Runnable() { @Override public void run() { 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("%d ms: %s", requestTime, this.toString()); } } }
public static void setupVolleyQueue() { requestQueue = Volley.newRequestQueue(mContext, VolleyUtils.getHTTPClientStack(mContext)); imageLoader = new ImageLoader(requestQueue, getBitmapCache()); VolleyLog.setTag(AppLog.TAG); // http://stackoverflow.com/a/17035814 imageLoader.setBatchedResponseDelay(0); }
/** Reads the contents of HttpEntity into a byte[]. */ private byte[] entityToBytes(HttpResponse httpResponse) throws IOException, ServerError { // private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError { HttpEntity entity = httpResponse.getEntity(); PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength()); byte[] buffer = null; try { // InputStream in = entity.getContent(); Header contentEncoding = httpResponse.getFirstHeader("Content-Encoding"); InputStream in = entity.getContent(); if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) { in = new GZIPInputStream(in); } if (in == null) { throw new ServerError(); } buffer = mPool.getBuf(1024); int count; while ((count = in.read(buffer)) != -1) { bytes.write(buffer, 0, count); } return bytes.toByteArray(); } finally { try { // Close the InputStream and release the resources by "consuming the content". entity.consumeContent(); } catch (IOException e) { // This can happen if there was an exception above that left the entity in // an invalid state. VolleyLog.v("Error occured when calling consumingContent"); } mPool.returnBuf(buffer); bytes.close(); } }
private void buildMultipartEntity() { entity.addPart(FILE_PART_NAME, new FileBody(mFilePart)); try { entity.addPart(STRING_PART_NAME, new StringBody(mStringPart)); } catch (UnsupportedEncodingException e) { VolleyLog.e("UnsupportedEncodingException"); } }
public <T> void addToRequestQueue(Request<T> req, String tag) { // set the default tag if tag is empty req.setTag(TextUtils.isEmpty(tag) ? "TAG" : tag); VolleyLog.d("Adding request to queue: %s", req.getUrl()); getRequestQueue().add(req); }
protected void finalize() throws Throwable { if (!this.mFinished) { finish("Request on the loose"); VolleyLog.e( "Marker log finalized without finish() - uncaught exit point for request", new Object[0]); } }
/** * Prunes the cache to fit the amount of bytes specified. * * @param neededSpace The amount of bytes we are trying to fit into the cache. */ 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(); Iterator<Map.Entry<String, CacheHeader>> iterator = mEntries.entrySet().iterator(); // 遍历缓存集合 while (iterator.hasNext()) { Map.Entry<String, CacheHeader> entry = iterator.next(); // 删除缓存集合头部CacheHeader对象对应的缓存文件, CacheHeader e = entry.getValue(); boolean deleted = getFileForKey(e.key).delete(); if (deleted) { mTotalSize -= e.size; // 删除头部元素后当前缓存的大小 } else { VolleyLog.d( "Could not delete cache entry for key=%s, filename=%s", e.key, getFilenameForKey(e.key)); } iterator.remove(); // 删除缓存集合头部CacheHeader对象 prunedFiles++; if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) { // mTotalSize:当前缓存的大小 // neededSpace:即将添加到缓存文件之中原始响应内容的大小 // mMaxCacheSizeInBytes:缓存最大值限制 // HYSTERESIS_FACTOR:缓存最高水准线(mMaxCacheSizeInBytes的百分之多少,其默认值为0.9) break; } } if (VolleyLog.DEBUG) { VolleyLog.v( "pruned %d files, %d bytes, %d ms", prunedFiles, (mTotalSize - before), SystemClock.elapsedRealtime() - startTime); } }
/** Removes the specified key from the cache if it exists. */ @Override public synchronized void remove(String key) { boolean deleted = getFileForKey(key).delete(); removeEntry(key); if (!deleted) { VolleyLog.d( "Could not delete cache entry for key=%s, filename=%s", key, getFilenameForKey(key)); } }
@Override public byte[] getBody() throws AuthFailureError { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { entity.writeTo(bos); } catch (IOException e) { VolleyLog.e("IOException writing to ByteArrayOutputStream"); } return bos.toByteArray(); }
public byte[] getBody() { try { return this.mRequestBody == null ? null : this.mRequestBody.getBytes("utf-8"); } catch (UnsupportedEncodingException var2) { VolleyLog.wtf( "Unsupported Encoding while trying to get the bytes of %s using %s", new Object[] {this.mRequestBody, "utf-8"}); return null; } }
/** Loads the image for the view if it isn't already loaded. */ private void loadImageIfNecessary() { int width = getWidth(); int height = getHeight(); // if the view's bounds aren't known yet, hold off on loading the image. if (width == 0 && height == 0) { return; } // if the URL to be loaded in this view is empty, cancel any old requests and clear the // currently loaded image. if (TextUtils.isEmpty(mUrl)) { if (mImageContainer != null) { mImageContainer.cancelRequest(); mImageContainer = null; } setImageBitmap(null); VolleyLog.d(TAG, "Not loading image"); return; } // if there was an old request in this view, check if it needs to be canceled. if (mImageContainer != null && mImageContainer.getRequestUrl() != null) { if (mImageContainer.getRequestUrl().equals(mUrl)) { // if the request is from the same URL, return. return; } else { // if there is a pre-existing request, cancel it if it's fetching a different URL. mImageContainer.cancelRequest(); setImageBitmap(null); } } // The pre-existing content of this view didn't match the current URL. Load the new image // from the network. VolleyLog.d(TAG, "Start loading image"); ImageContainer newContainer = mImageLoader.get(mUrl, ImageLoader.getImageListener(this, mDefaultImageId, mErrorImageId)); // update the ImageContainer to be the new bitmap container. mImageContainer = newContainer; }
@Override public byte[] getBody() { try { return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET); } catch (UnsupportedEncodingException uee) { VolleyLog.wtf( "Unsupported Encoding while trying to get the bytes of %s using %s", mRequestBody, PROTOCOL_CHARSET); return null; } }
/** Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete. */ private void logSlowRequests( long requestLifetime, Request<?> request, byte[] responseContents, StatusLine statusLine) { if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) { VolleyLog.d( "HTTP response for request=<%s> [lifetime=%d], [size=%s], " + "[rc=%d], [retryCount=%s]", request, requestLifetime, responseContents != null ? responseContents.length : "null", statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount()); } }
/** Clears the cache. Deletes all cached files from disk. */ @Override public synchronized void clear() { File[] files = mRootDirectory.listFiles(); if (files != null) { for (File file : files) { file.delete(); } } mEntries.clear(); mTotalSize = 0; VolleyLog.d("Cache cleared."); }
@Override public byte[] getBody() throws AuthFailureError { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { entity.writeTo(bos); } catch (IOException e) { VolleyLog.e("IOException writing to ByteArrayOutputStream"); } // return bos.toByteArray(); System.out.println("write entity:" + byteArrayGlobal.toString()); return byteArrayGlobal; }
/** * Cancels all requests in this queue with the given tag. Tag must be non-null and equality is by * identity. */ public void cancelAll(final Object tag) { if (tag == null) { throw new IllegalArgumentException("Cannot cancelAll with a null tag"); } VolleyLog.v("Cancel Requests for Tag %s", tag.toString()); cancelAll( new RequestFilter() { @Override public boolean apply(Request<?> request) { return request.getTag() == tag; } }); }
private void buildMultipartEntity() { entity.addPart( "profile_picture", new FileBody(new File("/storage/emulated/0/Pictures/VSCOCam/2015-07-31 11.55.14 1.jpg"))); try { entity.addPart("user_id", new StringBody("15")); entity.addPart("name", new StringBody("Bogs")); entity.addPart("gender", new StringBody("Male")); entity.addPart("date_birth", new StringBody("1999-12-5")); entity.addPart("breed", new StringBody("monkey")); } catch (UnsupportedEncodingException e) { VolleyLog.e("UnsupportedEncodingException"); } }
public byte[] getBody() { if (mRequestBody == null) { return null; } byte abyte0[]; try { abyte0 = mRequestBody.getBytes("utf-8"); } catch (UnsupportedEncodingException unsupportedencodingexception) { VolleyLog.wtf( "Unsupported Encoding while trying to get the bytes of %s using %s", new Object[] {mRequestBody, "utf-8"}); return null; } return abyte0; }
/** Writes the contents of this CacheHeader to the specified OutputStream. CacheHeader转换成文件 */ public boolean writeHeader(OutputStream os) { try { writeInt(os, CACHE_MAGIC); writeString(os, key); writeString(os, etag == null ? "" : etag); writeLong(os, serverDate); writeLong(os, ttl); writeLong(os, softTtl); writeStringStringMap(responseHeaders, os); os.flush(); return true; } catch (IOException e) { VolleyLog.d("%s", e.toString()); return false; } }
/** * Adds a Request to the dispatch queue. * * @param request The request to service * @return The passed-in request */ 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); // Rewrite the url, in case of GET requests if (mUrlRewriter != null) { request.setUrl(mUrlRewriter.rewriteUrl(request)); } 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<Request> stagedRequests = mWaitingRequests.get(cacheKey); if (stagedRequests == null) { stagedRequests = new LinkedList<Request>(); } stagedRequests.add(request); mWaitingRequests.put(cacheKey, stagedRequests); if (VolleyLog.sDebug) { 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; } }
/** Puts the entry with the specified key into the cache. */ @Override public synchronized void put(String key, Entry entry) { pruneIfNeeded(entry.data.length); File file = getFileForKey(key); // 根据key找到缓存文件 try { FileOutputStream fos = new FileOutputStream(file); CacheHeader e = new CacheHeader(key, entry); // 通过Cache.Entry生成一个摘要(CacheHeader) e.writeHeader(fos); // 将摘要写入缓存文件之中 fos.write(entry.data); // 将内容写入缓存文件之中 fos.close(); putEntry(key, e); // 将摘要添加到缓存集合之中 return; } catch (IOException e) { } boolean deleted = file.delete(); if (!deleted) { VolleyLog.d("Could not clean up file %s", file.getAbsolutePath()); } }
public MultipartRequest( String url, Response.Listener<String> rListener, Response.ErrorListener eListener, @Nullable HashMap<String, String> head, @NonNull String stringPart, @NonNull File file, @Nullable Map<String, Object> param) { super(Method.POST, url, rListener, eListener); header = null; if (head == null) { header = new HashMap<>(); } else { header = (HashMap) head.clone(); } String boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"; header.put("Content-Type", "multipart/form-data; boundary=" + boundary); // build multi-part MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create(); entityBuilder.setBoundary(boundary); entityBuilder.addPart(stringPart, new FileBody(file)); if (param != null) { try { for (String key : param.keySet()) { Object obj = param.get(key); String input = obj.toString(); entityBuilder.addPart(key, new StringBody(input, ContentType.MULTIPART_FORM_DATA)); } } catch (Exception e) { VolleyLog.e("Fail to build multipart. " + e.getMessage()); e.printStackTrace(); } } entity = entityBuilder.build(); }
private static void addColumns2Map( Class<?> entityType, String primaryKeyFieldName, HashMap<String, Column> columnMap) { if (Object.class.equals(entityType)) return; try { Field[] fields = entityType.getDeclaredFields(); for (Field field : fields) { if (ColumnUtils.isTransient(field) || Modifier.isStatic(field.getModifiers())) { continue; } if (ColumnConverterFactory.isSupportColumnConverter(field.getType())) { if (!field.getName().equals(primaryKeyFieldName)) { Column column = new Column(entityType, field); if (!columnMap.containsKey(column.getColumnName())) { columnMap.put(column.getColumnName(), column); } } } else if (ColumnUtils.isForeign(field)) { Foreign column = new Foreign(entityType, field); if (!columnMap.containsKey(column.getColumnName())) { columnMap.put(column.getColumnName(), column); } } else if (ColumnUtils.isFinder(field)) { Finder column = new Finder(entityType, field); if (!columnMap.containsKey(column.getColumnName())) { columnMap.put(column.getColumnName(), column); } } } if (!Object.class.equals(entityType.getSuperclass())) { addColumns2Map(entityType.getSuperclass(), primaryKeyFieldName, columnMap); } } catch (Throwable e) { VolleyLog.e(e.getMessage(), e); } }
@Override public void run() { if (DEBUG) { VolleyLog.v("start new dispatcher"); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // Make a blocking call to initialize the cache. mCache.initialize(); while (true) { try { // Get a request from the cache triage queue, blocking until at least one is available. final Request<?> request = mCacheQueue.take(); request.addMarker("cache-queue-take"); // If the request has been canceled, don't bother dispatching it. if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // Attempt to retrieve this item from cache. Cache.Entry entry = mCache.get(request.getCacheKey()); if (entry == null) { request.addMarker("cache-miss"); // Cache miss; send off to the network dispatcher. mNetworkQueue.put(request); continue; } // If it is completely expired, just send it to the network. if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // We have a cache hit; parse its data for delivery back to the request. request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); // TODO request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { // Completely unexpired cache hit. Just deliver the response. mDelivery.postResponse(request, response); } else { // Soft-expired cache hit. We can deliver the cached response, // but we need to also send the request to the network for // refreshing. request.addMarker("cache-hit-refresh-needed"); request.setCacheEntry(entry); // Mark the response as intermediate. response.intermediate = true; // Post the intermediate response back to the user and have // the delivery then forward the request along to the network. mDelivery.postResponse( request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(request); } catch (InterruptedException e) { // Not much we can do about this. } } }); } } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } } }
protected void logError(String what, String url, long start) { long now = SystemClock.elapsedRealtime(); VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url); }