2012-10-05 25 views
14

Ứng dụng android của tôi lấy dữ liệu của nó bằng REST API. Tôi muốn thực hiện bộ đệm ẩn phía máy khách. Chúng tôi có bất kỳ lớp học sẵn có nào cho việc này không?Làm cách nào để triển khai bộ nhớ đệm trong ứng dụng android cho kết quả REST API?

nếu không, có phải bất kỳ mã nào mà tôi có thể sử dụng lại không? Tôi nhớ đã gặp lại đoạn mã đó vào lúc nào đó. Tuy nhiên tôi không thể tìm thấy nó.

Nếu không có công trình nào khác hoạt động, tôi sẽ tự viết. sau là cấu trúc cơ bản

public class MyCacheManager { 

static Map<String, Object> mycache; 

public static Object getData(String cacheid) { 
    return mycache.get(cacheid); 
} 

public static void putData(String cacheid, Object obj, int time) { 
    mycache.put(cacheid, obj); 
} 

} 

làm cách nào để kích hoạt thời gian cho các đối tượng được lưu trong bộ nhớ cache? cũng - whats cách tốt nhất để serialize? bộ nhớ cache phải được giữ nguyên ngay cả khi ứng dụng bị đóng và mở lại sau (nếu thời gian chưa hết hạn).

Cảm ơn Ajay

Trả lời

3

Một trong những cách tốt nhất là sử dụng Matthias KAPPLER của đốt cháy librarys để đưa ra yêu cầu http rằng lưu trữ các câu trả lời trong bộ nhớ (tham khảo yếu) và trong hồ sơ. Nó thực sự cấu hình để làm một hoặc khác hoặc cả hai.

Thư viện nằm ở đây: https://github.com/mttkay/ignition với các ví dụ nằm ở đây: https://github.com/mttkay/ignition/wiki/Sample-applications

Cá nhân, tôi yêu lib này từ khi nó được gọi là Droidfu

Hy vọng điều này sẽ giúp bạn nhiều như nó đã làm tôi Ajay!

9

Bây giờ tuyệt vời thư viện Volley phát hành trên Google I/O 2013 giúp cho cải thiện theo mọi vấn đề gọi REST API:

Volley is a library, nó là thư viện gọi Volley từ nhóm dev Android. giúp việc kết nối mạng cho các ứng dụng Android trở nên dễ dàng và quan trọng nhất, nhanh hơn. Nó quản lý việc xử lý và bộ nhớ đệm của các yêu cầu mạng và nó giúp các nhà phát triển tiết kiệm thời gian quý báu bằng cách viết cùng một mã gọi/mã bộ nhớ mạng một lần nữa và một lần nữa. Và một lợi ích nữa của việc có ít mã hơn là ít lỗi hơn và đó là tất cả các nhà phát triển muốn và nhắm đến.

Ví dụ cho volley: technotalkative

+0

Tuyệt vời! Bạn cũng có thể tìm thấy một số mẫu tốt của việc sử dụng Volley ở đây: https://github.com/stormzhang/AndroidVolley – Sam003

0

Đầu tiên kiểm tra các thiết bị được kết nối từ internet hay không.

public class Reachability { 

private final ConnectivityManager mConnectivityManager; 


public Reachability(Context context) { 
    mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
} 

public boolean isConnected() { 
    NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); 
    return networkInfo != null && networkInfo.isConnectedOrConnecting(); 
}} 

Nếu thiết bị được kết nối từ internet thì lấy dữ liệu từ API và lưu vào bộ nhớ cache để lấy dữ liệu từ bộ nhớ cache.

public class CacheManager { 

Cache<String, String> mCache; 
private DiskLruCache mDiskLruCache; 
private final Context mContext; 

public CacheManager(Context context) throws IOException { 
    mContext = context; 
    setUp(); 
    mCache = DiskCache.getInstanceUsingDoubleLocking(mDiskLruCache); 
} 

public void setUp() throws IOException { 
    File cacheInFiles = mContext.getFilesDir(); 
    int version = BuildConfig.VERSION_CODE; 

    int KB = 1024; 
    int MB = 1024 * KB; 
    int cacheSize = 400 * MB; 

    mDiskLruCache = DiskLruCache.open(cacheInFiles, version, 1, cacheSize); 
} 

public Cache<String, String> getCache() { 
    return mCache; 
} 

public static class DiskCache implements Cache<String, String> { 

    private static DiskLruCache mDiskLruCache; 
    private static DiskCache instance = null; 

    public static DiskCache getInstanceUsingDoubleLocking(DiskLruCache diskLruCache){ 
     mDiskLruCache = diskLruCache; 
     if(instance == null){ 
      synchronized (DiskCache.class) { 
       if(instance == null){ 
        instance = new DiskCache(); 
       } 
      } 
     } 
     return instance; 
    } 

    @Override 
    public synchronized void put(String key, String value) { 
     try { 
      if (mDiskLruCache != null) { 
       DiskLruCache.Editor edit = mDiskLruCache.edit(getMd5Hash(key)); 
       if (edit != null) { 
        edit.set(0, value); 
        edit.commit(); 
       } 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public synchronized String get(String key) { 
     try { 
      if (mDiskLruCache != null) { 
       DiskLruCache.Snapshot snapshot = mDiskLruCache.get(getMd5Hash(key)); 

       if (snapshot == null) { 
        // if there is a cache miss simply return null; 
        return null; 
       } 

       return snapshot.getString(0); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     // in case of error in reading return null; 
     return null; 
    } 

    @Override 
    public String remove(String key) { 
     // TODO: implement 
     return null; 
    } 

    @Override 
    public void clear() { 
     // TODO: implement 
    } 
} 

public static String getMd5Hash(String input) { 
    try { 
     MessageDigest md = MessageDigest.getInstance("MD5"); 
     byte[] messageDigest = md.digest(input.getBytes()); 
     BigInteger number = new BigInteger(1, messageDigest); 
     String md5 = number.toString(16); 

     while (md5.length() < 32) 
      md5 = "0" + md5; 

     return md5; 
    } catch (NoSuchAlgorithmException e) { 
     Log.e("MD5", e.getLocalizedMessage()); 
     return null; 
    } 
}} 

Tạo lớp CacheInterceptor để cache phản hồi mạng và xử lý các lỗi

public class CacheInterceptor implements Interceptor{ 
private final CacheManager mCacheManager; 
private final Reachability mReachability; 

public CacheInterceptor(CacheManager cacheManager, Reachability reachability) { 
    mCacheManager = cacheManager; 
    mReachability = reachability; 
} 

@Override 
public Response intercept(Chain chain) throws IOException { 
    Request request = chain.request(); 
    String key = request.url().toString(); 

    Response response; 
    if (mReachability.isConnected()) { 
     try { 
      response = chain.proceed(request); 
      Response newResponse = response.newBuilder().build(); 

      if (response.isSuccessful()) { 
       if (response.code() == 204) { 
        return response; 
       } 
       // save to cache this success model. 
       mCacheManager.getCache().put(key, newResponse.body().string()); 

       // now we know that we definitely have a cache hit. 
       return getCachedResponse(key, request); 
      }else if (response.code() >= 500) { // accommodate all server errors 

       // check if there is a cache hit or miss. 
       if (isCacheHit(key)) { 
        // if data is in cache, the return the data from cache. 
        return getCachedResponse(key, request); 
       }else { 
        // if it's a miss, we can't do much but return the server state. 
        return response; 
       } 

      }else { // if there is any client side error 
       // forward the response as it is to the business layers to handle. 
       return response; 
      } 
     } catch (ConnectException | UnknownHostException e) { 
      // Internet connection exception. 
      e.printStackTrace(); 
     } 
    } 

    // if somehow there is an internet connection error 
    // check if the data is already cached. 
    if (isCacheHit(key)) { 
     return getCachedResponse(key, request); 
    }else { 
     // if the data is not in the cache we'll throw an internet connection error. 
     throw new UnknownHostException(); 
    } 
} 

private Response getCachedResponse(String url, Request request) { 
    String cachedData = mCacheManager.getCache().get(url); 

    return new Response.Builder().code(200) 
      .body(ResponseBody.create(MediaType.parse("application/json"), cachedData)) 
      .request(request) 
      .protocol(Protocol.HTTP_1_1) 
      .build(); 
} 

public boolean isCacheHit(String key) { 
    return mCacheManager.getCache().get(key) != null; 
}} 

Bây giờ thêm đánh chặn này trong OkHttpClient trong khi tạo ra các dịch vụ sử dụng Retrofit.

public final class ServiceManager { 
private static ServiceManager mServiceManager; 

public static ServiceManager get() { 
    if (mServiceManager == null) { 
     mServiceManager = new ServiceManager(); 
    } 
    return mServiceManager; 
} 

public <T> T createService(Class<T> clazz, CacheManager cacheManager, Reachability reachability) { 
    return createService(clazz, HttpUrl.parse(ServiceApiEndpoint.SERVICE_ENDPOINT), cacheManager, reachability); 
} 

private <T> T createService(Class<T> clazz, HttpUrl parse, CacheManager cacheManager, Reachability reachability) { 
    Retrofit retrofit = getRetrofit(parse, cacheManager, reachability); 
    return retrofit.create(clazz); 
} 

public <T> T createService(Class<T> clazz) { 
    return createService(clazz, HttpUrl.parse(ServiceApiEndpoint.SERVICE_ENDPOINT)); 
} 

private <T> T createService(Class<T> clazz, HttpUrl parse) { 
    Retrofit retrofit = getRetrofit(parse); 
    return retrofit.create(clazz); 
} 

private <T> T createService(Class<T> clazz, Retrofit retrofit) { 
    return retrofit.create(clazz); 
} 

private Retrofit getRetrofit(HttpUrl httpUrl, CacheManager cacheManager, Reachability reachability) { 
    return new Retrofit.Builder() 
      .baseUrl(httpUrl) 
      .client(createClient(cacheManager, reachability)) 
      .addConverterFactory(getConverterFactory()) 
      .build(); 
} 

private OkHttpClient createClient(CacheManager cacheManager, Reachability reachability) { 
    return new OkHttpClient.Builder().addInterceptor(new CacheInterceptor(cacheManager, reachability)).build(); 
} 

private Retrofit getRetrofit(HttpUrl parse) { 
    return new Retrofit.Builder() 
      .baseUrl(parse) 
      .client(createClient()) 
      .addConverterFactory(getConverterFactory()).build(); 
} 

private Retrofit getPlainRetrofit(HttpUrl httpUrl) { 
    return new Retrofit.Builder() 
      .baseUrl(httpUrl) 
      .client(new OkHttpClient.Builder().build()) 
      .addConverterFactory(getConverterFactory()) 
      .build(); 
} 

private Converter.Factory getConverterFactory() { 
    return GsonConverterFactory.create(); 
} 

private OkHttpClient createClient() { 
    return new OkHttpClient.Builder().build(); 
}} 

giao diện bộ nhớ cache

public interface Cache<K, V> { 

void put(K key, V value); 

V get(K key); 

V remove(K key); 

void clear();} 
Các vấn đề liên quan