@Override
  public void onRequestComplete(OnRequestCompleteData data) {
    BodyCacher cacher = data.state.getParcelable("body-cacher");
    if (cacher == null) return;

    try {
      if (data.exception != null) cacher.abort();
      else cacher.commit();
    } catch (Exception e) {
    }
  }
  // step 3) if this is a conditional cache request, serve it from the cache if necessary
  // otherwise, see if it is cacheable
  @Override
  public void onBodyDecoder(OnBodyData data) {
    CachedSocket cached =
        (CachedSocket)
            com.koushikdutta.async.Util.getWrappedSocket(data.socket, CachedSocket.class);
    if (cached != null) return;

    CacheData cacheData = data.state.getParcelable("cache-data");
    if (cacheData != null) {
      if (cacheData.cachedResponseHeaders.validate(data.headers)) {
        data.headers = cacheData.cachedResponseHeaders.combine(data.headers);
        data.headers
            .getHeaders()
            .setStatusLine(cacheData.cachedResponseHeaders.getHeaders().getStatusLine());

        conditionalCacheHitCount++;

        BodySpewer bodySpewer = new BodySpewer();
        bodySpewer.cacheResponse = cacheData.candidate;
        bodySpewer.setDataEmitter(data.bodyEmitter);
        data.bodyEmitter = bodySpewer;
        bodySpewer.spew();
        return;
      }

      // did not validate, so fall through and cache the response
      data.state.remove("cache-data");
    }

    if (!caching) return;

    if (!data.headers.isCacheable(data.request.getHeaders())
        || !data.request.getMethod().equals(AsyncHttpGet.METHOD)) {
      /*
       * Don't cache non-GET responses. We're technically allowed to cache
       * HEAD requests and some POST requests, but the complexity of doing
       * so is high and the benefit is low.
       */
      networkCount++;
      return;
    }

    String key = uriToKey(data.request.getUri());
    RawHeaders varyHeaders =
        data.request.getHeaders().getHeaders().getAll(data.headers.getVaryFields());
    Entry entry = new Entry(data.request.getUri(), varyHeaders, data.request, data.headers);
    DiskLruCache.Editor editor = null;
    BodyCacher cacher = new BodyCacher();
    try {
      editor = cache.edit(key);
      if (editor == null) {
        // Log.i(LOGTAG, "can't cache");
        return;
      }
      entry.writeTo(editor);

      cacher.cacheRequest = new CacheRequestImpl(editor);
      if (cacher.cacheRequest.getBody() == null) return;
      //            cacher.cacheData =
      cacher.setDataEmitter(data.bodyEmitter);
      data.bodyEmitter = cacher;

      data.state.putParcelable("body-cacher", cacher);
      cacheStoreCount++;
    } catch (Exception e) {
      // Log.e(LOGTAG, "error", e);
      if (cacher.cacheRequest != null) cacher.cacheRequest.abort();
      cacher.cacheRequest = null;
      networkCount++;
    }
  }