Skip to content

Commit

Permalink
Polling and Converter.Factory customization support (#10)
Browse files Browse the repository at this point in the history
* Allow customization of converter factories in RetrofitServices

* Polling mechanisms

* Remove unnecesary Manifest stuff

* Remove unnecesary string

* Add comment as to why Timer is fine

* Update Wolmo version to v1.3.1
  • Loading branch information
SpicyCactuar authored Nov 23, 2017
1 parent fd4efaf commit 59cc759
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 12 deletions.
2 changes: 1 addition & 1 deletion networking/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ android {
}

buildscript {
ext.wolmo_version = 'v1.2.0'
ext.wolmo_version = 'v1.3.1'
ext.retrofit_version = '2.3.0'
ext.okhttp3_version = '3.9.0'
}
Expand Down
9 changes: 4 additions & 5 deletions networking/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ar.com.wolox.wolmo.networking">
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="ar.com.wolox.wolmo.networking">

<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"/>
android:supportsRtl="true"/>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ar.com.wolox.wolmo.networking.exception;

import android.support.annotation.NonNull;

import retrofit2.Call;

/**
* {@link Exception} raised when polling an endpoint, for a maximum amount of tries, consumes all
* of its tries available (ie: reaches 0).
*/
public final class PollRunOutOfTriesException extends RuntimeException {

public PollRunOutOfTriesException(@NonNull Call call) {
super("Polling to " + call.request().url().toString() + " failed after running out of tries");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@

import com.google.gson.Gson;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ar.com.wolox.wolmo.networking.retrofit.serializer.BaseGsonBuilder;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

Expand All @@ -52,11 +55,19 @@ public abstract class RetrofitServices {
*/
public void init() {
mServices = new HashMap<>();
mRetrofit = new Retrofit.Builder()
mRetrofit = buildRetrofitInstance();
}

private Retrofit buildRetrofitInstance() {
Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.baseUrl(getApiEndpoint())
.addConverterFactory(GsonConverterFactory.create(getGson()))
.client(getOkHttpClient())
.build();
.client(getOkHttpClient());

for (Converter.Factory converterFactory : getConverterFactories()) {
retrofitBuilder.addConverterFactory(converterFactory);
}

return retrofitBuilder.build();
}

/**
Expand All @@ -67,6 +78,24 @@ public void init() {
@NonNull
public abstract String getApiEndpoint();

/**
* Allows configuration of the {@link Converter.Factory} to be used by {@link Retrofit}.
* The default implementation returns a list with a single {@link GsonConverterFactory}
* instance. The {@link} must not contain a {@code null} {@link Converter.Factory}.
* <p/>
* An important implicit aspect of what is returned in this method is that {@link Retrofit}
* iterates through the list <bold>in order</bold> to match a {@link okhttp3.ResponseBody}
* with a {@link Converter}.
* <p/>
* Implementations should pay attention to these because, for example,
* {@link GsonConverterFactory} <bold>always</bold> matches, thus preventing the fall-through.
*
* @return the {@link List} of {@link GsonConverterFactory} to use.
*/
protected List<Converter.Factory> getConverterFactories() {
return Collections.singletonList(GsonConverterFactory.create(getGson()));
}

/**
* Returns an instance of Gson to use for conversion.
* This method calls <i>initGson(builder)</i> to configure the Gson Builder.
Expand Down Expand Up @@ -138,7 +167,7 @@ private boolean isInitialized() {
* @param <T> Service class
* @return service
*/
public <T> T getService(@NonNull Class<T> clazz) {
public final <T> T getService(@NonNull Class<T> clazz) {
if (!isInitialized()) throw new RuntimeException("RetrofitServices is not initialized! " +
"Must call init() at least once before calling getService(clazz)");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package ar.com.wolox.wolmo.networking.utils;

import android.support.annotation.IntRange;
import android.support.annotation.NonNull;

import com.android.internal.util.Predicate;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import ar.com.wolox.wolmo.networking.exception.PollRunOutOfTriesException;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

/**
* Common uses of Retrofit's {@link Call}, {@link Callback} and their interactions.
*/
public class CallUtils {

private CallUtils() {}

/**
* Polls with a delay in-between calls.
*
* @param tries amount of tries
* @param call to poll
* @param pollingCondition that dictates whether to keep polling
* @param callback to be notified when polling ends
* @param delay to apply in-between calls
* @param timeoutUnit to convert delay
* @return a {@link Timer} which is controlling the polling
*/
public static <T> Timer pollWithDelay(@IntRange(from = 1) final int tries,
@NonNull final Call<T> call,
@NonNull final Predicate<Response<T>> pollingCondition,
@NonNull final Callback<T> callback,
@IntRange(from = 0) long delay,
@NonNull TimeUnit timeoutUnit) {
// Timer can be used safely since Retrofit callback is called on UiThread
Timer pollingTimer = new Timer();
pollWithDelay(tries, call, pollingCondition, callback,
timeoutUnit.toMillis(delay), pollingTimer);
return pollingTimer;
}

private static <T> void pollWithDelay(@IntRange(from = 1) final int triesRemaining,
@NonNull final Call<T> call,
@NonNull final Predicate<Response<T>> pollingCondition,
@NonNull final Callback<T> callback,
@IntRange(from = 0) long delayInMillis,
@NonNull final Timer pollingTimer) {
if (triesRemaining <= 0) callback.onFailure(call, new PollRunOutOfTriesException(call));

call.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
if (!pollingCondition.apply(response)) {
callback.onResponse(call, response);
return;
}

pollingTimer.schedule(new TimerTask() {
@Override
public void run() {
pollWithDelay(triesRemaining - 1, call.clone(),
pollingCondition, callback, delayInMillis, pollingTimer);
}
}, delayInMillis);
}

@Override
public void onFailure(Call<T> call, Throwable t) {
callback.onFailure(call, t);
}
});
}

}
1 change: 0 additions & 1 deletion networking/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<resources>
<string name="app_name">Networking</string>

<!-- General -->
<string name="unknown_error">Whoops! Something went wrong</string>
Expand Down

0 comments on commit 59cc759

Please sign in to comment.