2012-10-05 15 views
14

La mia app Android ottiene i suoi dati usando l'API REST. Voglio avere implementato il caching del client. Abbiamo qualche classe incorporata per questo?Come implementare il caching nell'app per Android per i risultati dell'API REST?

in caso contrario, si tratta di un codice che posso riutilizzare? Ricordo di aver trovato questo codice qualche volta indietro. Tuttavia non riesco a trovarlo.

Se nient'altro funziona, scriverò il mio. segue è struttura di base

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); 
} 

} 

Come faccio ad attivare il tempo per gli oggetti memorizzati nella cache? anche - qual è il modo migliore per serializzare? la cache dovrebbe essere intatta anche se l'app viene chiusa e riaperta in seguito (se il tempo non è scaduto).

Grazie Ajay

risposta

3

Uno dei modi migliori è quello di utilizzare Matthias Käppler di acceso librarys per effettuare richieste HTTP che memorizza nella cache le risposte a memoria (riferimento debole) e sul file. È davvero configurabile per fare l'uno o l'altro o entrambi.

La biblioteca si trova qui: https://github.com/mttkay/ignition con esempi si trova qui: https://github.com/mttkay/ignition/wiki/Sample-applications

Personalmente, amo questo lib da quando si chiamava Droidfu

Spero che questo ti aiuta quanto mi ha fatto Ajay!

9

Ora impressionante Volley biblioteca rilasciato su Google I/O 2013, che aiuta a migliorare su tutti i problemi di chiamare API REST:

Volley is a library, è libreria chiamata Volley dal team di sviluppo di Android. ciò rende la rete per le app Android più facile e, soprattutto, più veloce. Gestisce l'elaborazione e la memorizzazione nella cache delle richieste di rete e risparmia tempo prezioso agli sviluppatori dalla scrittura dello stesso codice di chiamata/cache di rete più e più volte. E un altro vantaggio di avere meno codice è il minor numero di bug e tutti gli sviluppatori vogliono e mirano.

Esempio volley: technotalkative

+0

Grande! Puoi anche trovare alcuni esempi di utilizzo di Volley qui: https://github.com/stormzhang/AndroidVolley – Sam003

0

Controllare innanzi il dispositivo è collegato da Internet o meno.

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(); 
}} 

Se il dispositivo è collegato da internet quindi ottenere i dati da API e la cache è altro ottenere i dati dalla 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; 
    } 
}} 

creare la classe CacheInterceptor mettere in cache la risposta della rete e gestire gli errori

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; 
}} 

Ora aggiungete il quest'interceptor in OkHttpClient durante la creazione del servizio utilizzando 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(); 
}} 

interfaccia cache

public interface Cache<K, V> { 

void put(K key, V value); 

V get(K key); 

V remove(K key); 

void clear();} 
Problemi correlati