Skip to content

Instantly share code, notes, and snippets.

@TechIsFun
Last active January 11, 2016 10:04
Show Gist options
  • Select an option

  • Save TechIsFun/0013bdfd4e65fe6e6f7d to your computer and use it in GitHub Desktop.

Select an option

Save TechIsFun/0013bdfd4e65fe6e6f7d to your computer and use it in GitHub Desktop.
package com.example;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import com.example.networking.ApiService;
import com.example.networking.response.ExampleResponse;
import com.google.gson.Gson;
import java.util.HashMap;
import rx.Observable;
import timber.log.Timber;
public class ExampleDataManager {
private static final long MAX_AGE = 10 * 60 * 1000; // 10 minutes
private SharedPreferences mSharedPreferences;
private ApiService mApiService;
private HashMap<String, ExampleResponse> mMemoryCache = new HashMap<>();
private Gson mGson = new Gson();
public ExampleDataManager(SharedPreferences sharedPreferences,
ApiService apiService) {
mSharedPreferences = sharedPreferences;
mApiService = apiService;
}
public Observable<ExampleResponse> observeExampleResponse() {
return Observable.concat(fromMemory(), fromDisk(), fromNetwork())
.first(response -> isValid(response))
.onErrorResumeNext(throwable -> fallbackToDiskCache());
}
protected Observable<ExampleResponse> fromNetwork() {
return mApiService.getExampleObject()
.doOnNext(exampleResponse -> exampleResponse.setUpdatedAt(now()))
.doOnNext(exampleResponse -> cacheInMemory(exampleResponse))
.doOnNext(exampleResponse -> cacheOnDisk(exampleResponse))
.compose(logSource("NETWORK"));
}
private Observable<ExampleResponse> fallbackToDiskCache() {
Timber.v("fallback to disk cache");
return fromDisk();
}
protected void cacheOnDisk(ExampleResponse exampleResponse) {
String json = mGson.toJson(exampleResponse);
mSharedPreferences.edit().putString(getPrefKey(), json).apply();
}
protected Observable<ExampleResponse> fromDisk() {
Observable<ExampleResponse> observable = Observable.create(subscriber -> {
ExampleResponse exampleResponse = readFromPreferences();
if (exampleResponse != null) {
subscriber.onNext(exampleResponse);
}
subscriber.onCompleted();
});
return observable.doOnNext(data -> cacheInMemory(data))
.compose(logSource("DISK"));
}
private ExampleResponse readFromPreferences() {
String json = mSharedPreferences.getString(getPrefKey(), null);
try {
return mGson.fromJson(json, ExampleResponse.class);
} catch (Exception e) {
Timber.v(e, "ignored");
}
return null;
}
protected void cacheInMemory(@NonNull ExampleResponse exampleResponse) {
mMemoryCache.put(exampleResponse);
}
protected Observable<ExampleResponse> fromMemory() {
Observable<ExampleResponse> observable = Observable.create(subscriber -> {
subscriber.onNext(mMemoryCache.get());
subscriber.onCompleted();
});
return observable.compose(logSource("MEMORY"));
}
private boolean isValid(ExampleResponse exampleResponse) {
return exampleResponse != null && !isExpired(exampleResponse.getUpdatedAt());
}
protected void clearCache() {
mMemoryCache.remove();
mSharedPreferences.edit().remove(getPrefKey()).apply();
}
private String getPrefKey() {
// TODO: return a constant value or generete a key
}
private static long now() {
return System.currentTimeMillis();
}
private static boolean isExpired(long timestamp) {
return System.currentTimeMillis() - timestamp > MAX_AGE;
}
private Observable.Transformer<ExampleResponse, ExampleResponse> logSource(final String source) {
return dataObservable -> dataObservable.doOnNext(data -> {
if (data == null) {
Timber.v(source + " does not have any data.");
} else if (!isValid(data)) {
Timber.v(source + " has stale data.");
} else {
Timber.v(source + " has the data you are looking for!");
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment