Created
October 8, 2017 16:13
-
-
Save ntakouris/93605cb7a0d50e59ba200c115eb8f8a9 to your computer and use it in GitHub Desktop.
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
package com.eventora.mobile.app.util; | |
import android.arch.lifecycle.LiveData; | |
import android.arch.lifecycle.MediatorLiveData; | |
import android.arch.lifecycle.MutableLiveData; | |
import android.support.annotation.MainThread; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.annotation.WorkerThread; | |
import com.eventora.mobile.app.AppExecutors; | |
import retrofit2.Call; | |
import retrofit2.Callback; | |
import retrofit2.Response; | |
/** | |
* Created by Zarkopafilis on 10/8/2017. | |
*/ | |
public abstract class NetworkBoundData<T> { | |
private final AppExecutors appExecutors; | |
private final MediatorLiveData<T> result = new MediatorLiveData<>(); | |
public NetworkBoundData(AppExecutors appExecutors) { | |
this.appExecutors = appExecutors; | |
LiveData<T> dbSource = loadFromDb(); | |
result.addSource(dbSource, data -> { | |
result.removeSource(dbSource); | |
if (shouldFetch(data)) { | |
fetchFromNetwork(dbSource); | |
} else { | |
result.addSource(dbSource, newData -> setValue(newData)); | |
} | |
}); | |
} | |
@MainThread | |
private void setValue(T newValue) { | |
if (!Objects.equals(result.getValue(), newValue)) { | |
result.setValue(newValue); | |
} | |
} | |
private void fetchFromNetwork(final LiveData<T> dbSource) { | |
Call<T> call = createCall(); | |
// we re-attach dbSource as a new source, it will dispatch its latest value quickly | |
result.addSource(dbSource, newData -> setValue(newData)); | |
call.enqueue(new Callback<T>() { | |
@Override | |
public void onResponse(Call<T> call, Response<T> response) { | |
if (isResponseValid(response)) { | |
MutableLiveData<T> networkSource = new MutableLiveData<>(); | |
networkSource.setValue(response.body()); | |
result.addSource(networkSource, newData -> { | |
result.removeSource(networkSource); | |
result.removeSource(dbSource); | |
//noinspection ConstantConditions | |
appExecutors.diskIO().execute(() -> { | |
saveCallResult(processResponse(newData)); | |
appExecutors.mainThread().execute(() -> | |
// we specially request a new live data, | |
// otherwise we will get immediately last cached value, | |
// which may not be updated with latest results received from network. | |
result.addSource(loadFromDb(), | |
otherNewData -> setValue(otherNewData)) | |
); | |
}); | |
}); | |
} | |
} | |
@Override | |
public void onFailure(Call<T> call, Throwable t) { | |
onFetchFailed(); | |
result.addSource(dbSource, | |
newData -> setValue(newData)); | |
} | |
}); | |
} | |
protected void onFetchFailed() { | |
} | |
public LiveData<T> asLiveData() { | |
return result; | |
} | |
@WorkerThread | |
protected T processResponse(T response) { | |
return response; | |
} | |
@WorkerThread | |
protected abstract void saveCallResult(@NonNull T item); | |
@MainThread | |
protected abstract boolean shouldFetch(@Nullable T data); | |
@NonNull | |
@MainThread | |
protected abstract LiveData<T> loadFromDb(); | |
@NonNull | |
@MainThread | |
protected abstract Call<T> createCall(); | |
@NonNull | |
@MainThread | |
protected abstract boolean isResponseValid(Response<T> call); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment