Last active
August 29, 2015 14:19
-
-
Save billmote/2911e438a3a855379f06 to your computer and use it in GitHub Desktop.
A cache for OkHttp calls that implements the Builder Pattern or can be called statically.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import com.androidfu.nowplaying.app.util.Log; | |
import com.androidfu.nowplaying.app.util.Preconditions; | |
import com.jakewharton.byteunits.DecimalByteUnit; | |
import com.squareup.okhttp.Cache; | |
import com.squareup.okhttp.OkHttpClient; | |
import java.io.File; | |
import java.io.IOException; | |
import java.util.concurrent.TimeUnit; | |
import hugo.weaving.DebugLog; | |
/** | |
* | |
*/ | |
@DebugLog | |
public final class CachingOkHttpClient { | |
private static final String TAG = "CachingOkHttpClient"; | |
private static final int DEFAULT_CONNECT_TIMEOUT = 10; | |
private static final int DEFAULT_WRITE_TIMEOUT = 10; | |
private static final int DEFAULT_READ_TIMEOUT = 10; | |
private static final long DEFAULT_DISK_CACHE_SIZE = DecimalByteUnit.MEGABYTES.toBytes(10); | |
private static volatile CachingOkHttpClient instance = null; | |
private final OkHttpClient client; | |
private Cache cache; | |
private CachingOkHttpClient(final Builder builder) { | |
this.client = new OkHttpClient(); | |
this.client.setConnectTimeout(builder.connectTimeout, TimeUnit.SECONDS); | |
this.client.setWriteTimeout(builder.writeTimeout, TimeUnit.SECONDS); | |
this.client.setReadTimeout(builder.readTimeout, TimeUnit.SECONDS); | |
try { | |
if (cache == null) { | |
Log.i(TAG, String.format("Creating response cache of %d bytes ...", DEFAULT_DISK_CACHE_SIZE)); | |
cache = new Cache(builder.directory, builder.diskCacheSize); | |
Log.i(TAG, "success."); | |
} | |
} catch (IOException e) { | |
Log.e(TAG, String.format("Error creating response cache: %s", e.getMessage()), e); | |
} | |
if (cache != null) { | |
client.setCache(cache); | |
} | |
} | |
/* | |
A static alternative to the Builder(). | |
*/ | |
public static CachingOkHttpClient with(Context context) { | |
if (instance == null) { | |
synchronized (CachingOkHttpClient.class) { | |
if (instance == null) { | |
instance = new Builder(context).build(); | |
} | |
} | |
} | |
return instance; | |
} | |
public OkHttpClient getClient() { | |
return client.clone(); //Shallow copy of OkHttpClient. All downstream clients share the same cache and each client can set their own interceptors etc. | |
} | |
public static class Builder { | |
private final Context context; | |
private int connectTimeout = DEFAULT_CONNECT_TIMEOUT; | |
private int writeTimeout = DEFAULT_WRITE_TIMEOUT; | |
private int readTimeout = DEFAULT_READ_TIMEOUT; | |
private long diskCacheSize = DEFAULT_DISK_CACHE_SIZE; | |
private File directory; | |
public Builder(Context context) { | |
Preconditions.checkNotNull(context, "context != null"); | |
this.context = context; | |
} | |
public Builder connectTimeout(int connectTimeout) { | |
Preconditions.checkArgument(connectTimeout > 0, "connectTimeout must be > 0"); | |
this.connectTimeout = connectTimeout; | |
return this; | |
} | |
public Builder writeTimeout(int writeTimeout) { | |
Preconditions.checkArgument(writeTimeout > 0, "writeTimeout must be > 0"); | |
this.writeTimeout = writeTimeout; | |
return this; | |
} | |
public Builder readTimeout(int readTimeout) { | |
Preconditions.checkArgument(readTimeout > 0, "readTimeout must be > 0"); | |
this.readTimeout = readTimeout; | |
return this; | |
} | |
public Builder diskCacheSize(long diskCacheSize) { | |
Preconditions.checkArgument(diskCacheSize > 0, "diskSize must be > 0"); | |
this.diskCacheSize = diskCacheSize; | |
return this; | |
} | |
public Builder file(File directory) { | |
Preconditions.checkNotNull(directory, "directory != null"); | |
this.directory = directory; | |
return this; | |
} | |
public CachingOkHttpClient build() { | |
ensureSaneDefaults(); | |
return new CachingOkHttpClient(this); | |
} | |
private void ensureSaneDefaults() { | |
if (directory == null) { | |
directory = new File(context.getCacheDir(), "http"); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.text.TextUtils; | |
/** | |
* Created by billmote on 4/26/15. | |
*/ | |
public final class Preconditions { | |
private Preconditions() { | |
throw new AssertionError("No instances."); | |
} | |
public static void checkArgument(boolean expression, Object errorMessage) { | |
if (!expression) { | |
throw new IllegalArgumentException(String.valueOf(errorMessage)); | |
} | |
} | |
public static void checkState(boolean expression, Object errorMessage) { | |
if (!expression) { | |
throw new IllegalStateException(String.valueOf(errorMessage)); | |
} | |
} | |
public static <T> T checkNotNull(T reference, String name) { | |
if (reference == null) { | |
throw new NullPointerException(name + " must not be null"); | |
} | |
return reference; | |
} | |
public static <T extends CharSequence> T checkNotBlank(T value, String name) { | |
if (TextUtils.isEmpty(value)) { | |
throw new IllegalArgumentException(name + " must not be blank"); | |
} | |
return value; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Application; | |
import com.androidfu.nowplaying.app.BuildConfig; | |
import com.androidfu.nowplaying.app.model.movies.Movie; | |
import com.google.gson.Gson; | |
import com.google.gson.GsonBuilder; | |
import com.google.gson.JsonDeserializationContext; | |
import com.google.gson.JsonDeserializer; | |
import com.google.gson.JsonElement; | |
import com.google.gson.JsonObject; | |
import com.google.gson.JsonParseException; | |
import com.squareup.okhttp.OkHttpClient; | |
import java.lang.reflect.Type; | |
import hugo.weaving.DebugLog; | |
import retrofit.RestAdapter; | |
import retrofit.client.OkClient; | |
import retrofit.converter.GsonConverter; | |
/** | |
* Created by billmote on 9/7/14. | |
*/ | |
@DebugLog | |
public class RestClient { | |
private ApiService apiService; | |
public RestClient(Application context, String endpoint, boolean enableLogging) { | |
OkHttpClient client = new CachingOkHttpClient.Builder(context).build().getClient(); | |
Gson gsonBuilder = new GsonBuilder() | |
.registerTypeAdapterFactory(new ItemTypeAdapterFactory()) | |
/* | |
Rotten Tomatoes returns an int when there's a valid value for runtime, but they | |
return an empty string when the value is null. Because they return different | |
JSON primitive types we have to create a custom TypeAdapter for our Movie.class. | |
*/ | |
.registerTypeAdapter(Movie.class, new JsonDeserializer<Movie>() { | |
@Override | |
public Movie deserialize(JsonElement arg0, Type arg1, JsonDeserializationContext arg2) throws JsonParseException { | |
JsonObject movieObject = arg0.getAsJsonObject(); | |
Gson gson = new Gson(); | |
Movie movie = gson.fromJson(arg0, Movie.class); | |
int runtime; | |
try { | |
runtime = movieObject.get("runtime").getAsInt(); | |
} catch (Exception e) { | |
runtime = 0; | |
} | |
movie.setMovieRuntime(runtime); | |
return movie; | |
} | |
}) | |
.setDateFormat("yyyy-MM-dd") | |
.setPrettyPrinting() | |
.excludeFieldsWithoutExposeAnnotation() | |
.create(); | |
RestAdapter restAdapter = new RestAdapter.Builder() | |
.setClient(new OkClient(client)) | |
.setLogLevel(BuildConfig.DEBUG && enableLogging ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE) | |
.setEndpoint(endpoint) | |
.setConverter(new GsonConverter(gsonBuilder, "UTF-8")) | |
.setRequestInterceptor(new SessionRequestInterceptor()) | |
.build(); | |
apiService = restAdapter.create(ApiService.class); | |
} | |
public ApiService getApiService() { | |
return apiService; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment