2013-05-27 48 views
48
public class CustomRequest extends JsonObjectRequest { 

    public CustomRequest(String url, JSONObject params, 
      Listener<JSONObject> listener, ErrorListener errorListener) 
      throws JSONException { 
     super(Method.POST,url, params, listener, 
       errorListener); 
     this.setShouldCache(Boolean.TRUE); 
    } 
} 

Tôi đã hy vọng rằng đoạn mã này sẽ đủ để tôi có được bộ nhớ đệm ngầm của các câu trả lời. Tôi không chắc chắn nếu nó hoạt động hay không, bởi vì tôi đã được theo giả định khi yêu cầu được gửi:Android Volley + JSONObjectRequest Caching

  1. nó sẽ nhấn cache đầu tiên và gửi đến onresponse

  2. sau đó khi kết quả đi qua từ máy chủ từ xa nó sẽ cung cấp nó vào onresponse

cập nhật:

tôi đã tìm cách tự lấy lại bộ nhớ cache và tái tạo lại nó i vào một JSONObject và gửi nó thông qua chức năng OnResponse nhưng điều đó dường như không hiệu quả khi xem xét có bộ nhớ đệm ngầm. Lớp JsonObjectRequest sẽ trả về JSONObject làm mục nhập được lưu trong bộ nhớ cache thay vì dữ liệu phản hồi thô.

Nhưng tôi vẫn muốn biết liệu tôi có mắc lỗi hay không.

Sự mơ hồ chỉ là do thiếu tài liệu, vì vậy tôi xin lỗi nếu tôi thiếu điều gì đó khá rõ ràng.

Trả lời

86

Xem câu trả lời này - Set expiration policy for cache using Google's Volley

Điều này có nghĩa Volley quyết định liệu bộ nhớ cache đáp ứng hay không chỉ dựa trên tiêu đề "Cache-Control" và sau đó "Hết hạn", "maxAge".

gì bạn có thể làm là thay đổi phương pháp này com.android.volley.toolbox.HttpHeaderParser.parseCacheHeaders(NetworkResponse response) và bỏ qua các tiêu đề, thiết lập entry.softTtlentry.ttl trường để bất cứ điều gì giá trị làm việc cho bạn và sử dụng phương pháp của bạn trong lớp yêu cầu của bạn. Dưới đây là một ví dụ:

/** 
* Extracts a {@link Cache.Entry} from a {@link NetworkResponse}. 
* Cache-control headers are ignored. SoftTtl == 3 mins, ttl == 24 hours. 
* @param response The network response to parse headers from 
* @return a cache entry for the given response, or null if the response is not cacheable. 
*/ 
public static Cache.Entry parseIgnoreCacheHeaders(NetworkResponse response) { 
    long now = System.currentTimeMillis(); 

    Map<String, String> headers = response.headers; 
    long serverDate = 0; 
    String serverEtag = null; 
    String headerValue; 

    headerValue = headers.get("Date"); 
    if (headerValue != null) { 
     serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue); 
    } 

    serverEtag = headers.get("ETag"); 

    final long cacheHitButRefreshed = 3 * 60 * 1000; // in 3 minutes cache will be hit, but also refreshed on background 
    final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely 
    final long softExpire = now + cacheHitButRefreshed; 
    final long ttl = now + cacheExpired; 

    Cache.Entry entry = new Cache.Entry(); 
    entry.data = response.data; 
    entry.etag = serverEtag; 
    entry.softTtl = softExpire; 
    entry.ttl = ttl; 
    entry.serverDate = serverDate; 
    entry.responseHeaders = headers; 

    return entry; 
} 

Sử dụng phương pháp này trong lớp Yêu cầu của bạn như thế này:

public class MyRequest extends com.android.volley.Request<MyResponse> { 

    ... 

    @Override 
    protected Response<MyResponse> parseNetworkResponse(NetworkResponse response) { 
     String jsonString = new String(response.data); 
     MyResponse MyResponse = gson.fromJson(jsonString, MyResponse.class); 
     return Response.success(MyResponse, HttpHeaderParser.parseIgnoreCacheHeaders(response)); 
    } 

} 
+1

điều này có nghĩa là bộ nhớ cache sẽ kéo dài hơn, onDestroy? Vì vậy, lần sau khi ứng dụng được tạo, ứng dụng sẽ tìm nạp từ bộ nhớ cache? – gaara87

+3

Có, bộ nhớ đệm được lưu không chỉ trong bộ nhớ mà còn trên đĩa (xem lớp DiskBasedCache để biết chi tiết). Để kiểm tra nhanh, hãy tải một số dữ liệu, thoát khỏi ứng dụng của bạn, tắt wifi hoặc 3g và nhập lại ứng dụng của bạn. Bạn cũng có thể chỉ định kích thước bộ nhớ cache trong trường mMaxCacheSizeInBytes. –

+2

Có, nó lưu trữ trong khi tôi đang ở trong ứng dụng, nhưng khi tôi thoát khỏi ứng dụng và quay trở lại ứng dụng, tìm nạp từ bộ nhớ cache trả về null. Do đó câu hỏi liệu nó có tồn tại ở giữa các vòng đời hoạt động hay không. – gaara87

5

oleksandr_yefremov cung cấp mã tuyệt vời mà có thể giúp bạn khi bạn đối phó với chiến lược bộ nhớ cache của Android Volley, đặc biệt là khi REST API có tiêu đề "Cache-Control" không đúng hoặc bạn chỉ muốn kiểm soát nhiều hơn cho chiến lược bộ nhớ cache ứng dụng của riêng mình.

Khóa là HttpHeaderParser.parseCacheHeaders(NetworkResponse response)). Nếu bạn muốn có chiến lược bộ nhớ cache của riêng bạn. Thay thế bằng parseIgnoreCacheHeaders(NetworkResponse response) trong lớp tương ứng.

Nếu lớp học của bạn kéo dài JsonObjectRequest, đi đến JsonObjectRequest và tìm

@Override 
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { 
    try { 
      String jsonString =new String(response.data, HttpHeaderParser.parseCharset(response.headers)); 
      return Response.success(new JSONObject(jsonString),HttpHeaderParser.parseCacheHeaders(response)); 
     }catch (UnsupportedEncodingException e) { 
      return Response.error(new ParseError(e)); 
     }catch (JSONException je) { 
      return Response.error(new ParseError(je)); 
     } 
} 

và thay thế HttpHeaderParser.parseCacheHeaders(response) với HttpHeaderParser.parseIgnoreCacheHeaders

+0

Có phải bằng cách nào đó có thể thực hiện điều đó với 'NetworkImageView' không? – fiddler

2

+1 cho oleksandr_yefremov và skyfishjy cũng có, và cung cấp ở đây một bê tông, lớp tái sử dụng thích hợp cho json hoặc các API dựa trên chuỗi khác:

public class CachingStringRequest extends StringRequest { 
    public CachingStringRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener) { 
     super(method, url, listener, errorListener); 
    } 

    public CachingStringRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) { 
     super(url, listener, errorListener); 
    } 

    @Override 
    protected Response<String> parseNetworkResponse(NetworkResponse response) { 
     String parsed; 
     try { 
      parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); 
     } catch (UnsupportedEncodingException e) { 
      parsed = new String(response.data); 
     } 
     return Response.success(parsed, parseIgnoreCacheHeaders(response)); 
    } 
} 

nơi chức năng parseIgnoreCacheHeaders() com es từ câu trả lời oleksandr_yefremov ở trên.Sử dụng lớp CachingStringRequest ở bất cứ đâu mà kết quả là json được lưu vào cache trong 3 phút (trực tiếp) và 24 giờ (hết hạn nhưng vẫn có sẵn). Yêu cầu mẫu:

CachingStringRequest stringRequest = new CachingStringRequest(MY_API_URL, callback); 

và trong hàm onResponse() của đối tượng gọi lại, phân tích cú pháp. Đặt bất kỳ giới hạn bộ nhớ cache nào bạn muốn - bạn có thể tham số hóa để thêm hết hạn tùy chỉnh theo yêu cầu.

Để giải trí, hãy thử điều này trong một ứng dụng đơn giản tải xuống json và hiển thị thông tin đã tải xuống. Đã lấp đầy bộ nhớ cache với bản tải xuống thành công đầu tiên, hãy xem kết xuất nhanh khi bạn thay đổi hướng trong khi bộ nhớ cache đang hoạt động (không có tải xuống nào xảy ra do lần truy cập bộ nhớ cache trực tiếp). Bây giờ hãy hủy ứng dụng, đợi 3 phút để bộ nhớ cache đó hết hạn (nhưng không phải 24 giờ để bộ nhớ cache bị xóa khỏi bộ nhớ cache), bật chế độ trên máy bay và khởi động lại ứng dụng. Cuộc gọi lại lỗi Volley sẽ xảy ra và cuộc gọi lại "thành công" onResponse() sẽ xuất hiện từ dữ liệu được lưu trong bộ nhớ cache, cho phép ứng dụng của bạn hiển thị cả nội dung và cũng biết/cảnh báo rằng nó đến từ bộ nhớ cache đã hết hạn.

Một cách sử dụng loại bộ nhớ đệm này là để giảm bớt Trình tải và các phương tiện khác để xử lý thay đổi định hướng. Nếu một yêu cầu đi qua một singleton Volley, và kết quả được lưu trữ, làm mới điều đó xảy ra thông qua thay đổi định hướng được kết xuất nhanh chóng từ bộ nhớ cache, tự động bởi Volley, mà không có Trình tải.

Tất nhiên, điều này không phù hợp với tất cả các yêu cầu. YMMV

0

Tôi đã có thể buộc Volley lưu tất cả các phản hồi bằng cách mở rộng StringRequest và thay thế yêu cầu tôi muốn buộc bộ nhớ cache với CachingStringRequest.

Trong phương pháp ghi đè parseNetworkResponse Tôi xóa các tiêu đề Cache-Control. Bằng cách này, Volley kiên trì phản hồi trong bộ nhớ đệm tích hợp sẵn.

public class CachingStringRequest extends StringRequest { 
    private static final String CACHE_CONTROL = "Cache-Control"; 

    public CachingStringRequest(int method, 
           String url, 
           Response.Listener<String> listener, 
           Response.ErrorListener errorListener) { 
     super(method, url, listener, errorListener); 
    } 

    @Override 
    protected Response<String> parseNetworkResponse(NetworkResponse response) { 
     // I do this to ignore "no-cache" headers 
     // and use built-in cache from Volley. 
     if (response.headers.containsKey(CACHE_CONTROL)) { 
      response.headers.remove(CACHE_CONTROL); 
     } 

     return super.parseNetworkResponse(response); 
    } 
}