Skip to content

Commit

Permalink
Fixed tests, added LifecycleRxJavaBinder, added leak canary, code cle…
Browse files Browse the repository at this point in the history
…an up and bug fixes
  • Loading branch information
Zeyad-37 committed Jun 15, 2017
1 parent 0e96ce2 commit a1b4792
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 84 deletions.
6 changes: 5 additions & 1 deletion sampleApp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ dependencies {
compile "com.android.support:palette-v7:$supportLibraryVersion"
compile 'com.android.support.constraint:constraint-layout:1.0.2'

// compile "android.arch.lifecycle:runtime:1.0.0-alpha1"
// compile "android.arch.lifecycle:runtime:1.0.0-alpha2"
compile "android.arch.lifecycle:extensions:1.0.0-alpha2"
compile "android.arch.lifecycle:reactivestreams:1.0.0-alpha2"
// Network
compile 'com.github.bumptech.glide:glide:3.7.0'
// Rx
Expand All @@ -135,6 +136,9 @@ dependencies {
compile "com.jakewharton:butterknife:$butterKnifeVersion"
annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
// Utilities
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
compile "org.parceler:parceler-api:$parcelerVersion"
annotationProcessor "org.parceler:parceler:$parcelerVersion"
compile("io.flowup:android-sdk:0.2.4") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import android.util.Log;

import com.rollbar.android.Rollbar;
import com.squareup.leakcanary.LeakCanary;
import com.zeyad.usecases.api.DataServiceConfig;
import com.zeyad.usecases.api.DataServiceFactory;

Expand Down Expand Up @@ -89,6 +90,12 @@ private static boolean checkDebuggable(Context context) {
public void onCreate() {
// initializeStrictMode();
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
Completable.fromAction(() -> {
// checkAppTampering(this);
initializeFlowUp();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.zeyad.usecases.app.components;

import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.LiveDataReactiveStreams;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.MaybeTransformer;
import io.reactivex.ObservableTransformer;
import io.reactivex.SingleTransformer;

/**
* @author by ZIaDo on 6/14/17.
*/
public class LifecycleRxJavaBinder {
public static <T> FlowableTransformer<T, T> applyFlowable(LifecycleOwner lifecycleOwner) {
return flowable -> {
LiveData<T> liveData = LiveDataReactiveStreams.fromPublisher(flowable);
return Flowable.fromPublisher(LiveDataReactiveStreams.toPublisher(lifecycleOwner, liveData));
};
}

public static <T> ObservableTransformer<T, T> applyObservable(LifecycleOwner lifecycleOwner,
BackpressureStrategy strategy) {
return observable -> {
LiveData<T> liveData = LiveDataReactiveStreams.fromPublisher(observable.toFlowable(strategy));
return Flowable.fromPublisher(LiveDataReactiveStreams
.toPublisher(lifecycleOwner, liveData)).toObservable();
};
}

public static <T> ObservableTransformer<T, T> applyObservable(LifecycleOwner lifecycleOwner) {
return observable -> {
LiveData<T> liveData = LiveDataReactiveStreams.fromPublisher(observable
.toFlowable(BackpressureStrategy.BUFFER));
return Flowable.fromPublisher(LiveDataReactiveStreams
.toPublisher(lifecycleOwner, liveData)).toObservable();
};
}

public static <T> SingleTransformer<T, T> applySingle(LifecycleOwner lifecycleOwner) {
return single -> {
LiveData<T> liveData = LiveDataReactiveStreams.fromPublisher(single.toFlowable());
return Flowable.fromPublisher(LiveDataReactiveStreams
.toPublisher(lifecycleOwner, liveData)).singleOrError();
};
}

public static <T> MaybeTransformer<T, T> applyMaybe(LifecycleOwner lifecycleOwner) {
return maybe -> {
LiveData<T> liveData = LiveDataReactiveStreams.fromPublisher(maybe.toFlowable());
return Flowable.fromPublisher(LiveDataReactiveStreams
.toPublisher(lifecycleOwner, liveData)).firstElement();
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@ FlowableTransformer<BaseEvent, UIModel<S>> uiModels() {
if (result.isLoading()) {
currentUIModel = UIModel.loadingState(new ResultBundle<>(event, bundle));
} else if (result.isSuccessful()) {
currentUIModel =
UIModel.successState(new ResultBundle<>(event,
successStateAccumulator.accumulateSuccessStates(
result.getBundle(), event, bundle)));
currentUIModel = UIModel
.successState(new ResultBundle<>(event, successStateAccumulator
.accumulateSuccessStates(result.getBundle(), event, bundle)));
} else {
currentUIModel = UIModel.errorState(result.getError(),
new ResultBundle<>(event, bundle));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
package com.zeyad.usecases.app.components.redux;

import static com.zeyad.usecases.app.components.redux.UIModel.ERROR;
import static com.zeyad.usecases.app.components.redux.UIModel.LOADING;
import static com.zeyad.usecases.app.components.redux.UIModel.SUCCESS;

/**
* @author by ZIaDo on 4/19/17.
*/
final class Result<B> {

private final boolean isLoading, isSuccessful;
private final Throwable error;
private final String state;
private final ResultBundle<?, B> bundle;

private Result(String state, boolean isLoading, Throwable error, boolean isSuccessful,
ResultBundle<?, B> bundle) {
private Result(boolean isLoading, Throwable error, boolean isSuccessful, ResultBundle<?, B> bundle) {
this.isLoading = isLoading;
this.error = error;
this.isSuccessful = isSuccessful;
this.bundle = bundle;
this.state = state;
}

static <B> Result<B> loadingResult() {
return new Result<>(LOADING, true, null, false, null);
return new Result<>(true, null, false, new ResultBundle<>("", null));
}

static <B> Result<B> errorResult(Throwable error) {
return new Result<>(ERROR, false, error, false, null);
return new Result<>(false, error, false, new ResultBundle<>("", null));
}

static <B> Result<B> successResult(ResultBundle<?, B> bundle) {
return new Result<>(SUCCESS, false, null, true, bundle);
return new Result<>(false, null, true, bundle);
}

boolean isLoading() {
Expand All @@ -48,7 +41,8 @@ boolean isSuccessful() {
}

B getBundle() {
return bundle != null && bundle.getBundle() != null ? bundle.getBundle() : (B) new Object();
B bundle = this.bundle.getBundle();
return bundle != null ? bundle : (B) new Object();
}

String getEvent() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Throwable getError() {
}

S getBundle() {
return bundle != null && bundle.getBundle() != null ? bundle.getBundle() : null;
return bundle.getBundle();
}

ResultBundle<?, S> getResultBundle() {
Expand All @@ -60,7 +60,7 @@ boolean isSuccessful() {
public String toString() {
return String.format("State: %s, Error: %s, Bundle type: %s, Key Selector: %s",
(state.equalsIgnoreCase(SUCCESS) ? state + ", event: " + bundle.getEvent() : state),
(error != null ? error.toString() : "null"),
(error != null ? error.getMessage() : "null"),
(getBundle() != null ? getBundle().getClass().getSimpleName() : "null"),
state.equalsIgnoreCase(LOADING) ? state : state + (bundle != null ?
bundle.toString() : ""));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public void initialize() {
viewModel = ViewModelProviders.of(this).get(UserListVM.class);
viewModel.init(getUserListStateSuccessStateAccumulator(), null, DataServiceFactory.getInstance());
events = Single.<BaseEvent>just(new GetPaginatedUsersEvent(0))
.doOnSuccess(event -> Log.d("GetUsersEvent", "fired!"))
.doOnSuccess(event -> Log.d("GetPaginatedUsersEvent", "fired!"))
.toObservable();
rxEventBus.toFlowable()
.compose(bindToLifecycle())
Expand All @@ -106,7 +106,9 @@ public void initialize() {
@Override
protected void onResume() {
super.onResume();
viewModel.getUser().compose(bindToLifecycle()).subscribe(user -> Log.d("Test", user.toString()),
viewModel.getUser()
.compose(bindToLifecycle())
.subscribe(user -> Log.d("Test", user.toString()),
throwable -> {
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ public void run() {
@Override
public Single<Boolean> evictCollection(@NonNull String idFieldName, @NonNull List<Long> list,
@NonNull Class dataClass) {
return Single.fromCallable(() -> Observable.fromIterable(list)
return Single.fromCallable(() -> list.isEmpty() ? false : Observable.fromIterable(list)
.map(aLong -> evictById(dataClass, idFieldName, aLong))
.reduce((aBoolean, aBoolean2) -> aBoolean && aBoolean2)
.blockingGet());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public class CloudStore implements DataStore {
private final FirebaseJobDispatcher mDispatcher;
private final Utils mUtils;
private final MemoryStore mMemoryStore;
boolean mCanPersist, canCache;

/**
* Construct a {@link DataStore} based on connections to the api (Cloud).
Expand All @@ -77,8 +76,6 @@ public CloudStore(ApiConnection apiConnection, DataBaseManager dataBaseManager,
mApiConnection = apiConnection;
mEntityDataMapper = entityDataMapper;
mDataBaseManager = dataBaseManager;
mCanPersist = Config.isWithRealm() || Config.isWithSQLite();
canCache = memoryStore != null;
mDispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(Config.getInstance().getContext()));
mMemoryStore = memoryStore;
mUtils = utils;
Expand Down
25 changes: 20 additions & 5 deletions usecases/src/test/java/com/zeyad/usecases/api/DataServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.zeyad.usecases.stores.CloudStore;
import com.zeyad.usecases.stores.DataStoreFactory;
import com.zeyad.usecases.stores.DiskStore;
import com.zeyad.usecases.stores.MemoryStore;

import org.json.JSONArray;
import org.json.JSONObject;
Expand Down Expand Up @@ -47,12 +48,17 @@ public class DataServiceTest {
public void setUp() throws Exception {
flowable = Flowable.just(true);
postRequest = new PostRequest.Builder(Object.class, false).build();
getRequest = new GetRequest.Builder(Object.class, false).build();
getRequest = new GetRequest.Builder(TestRealmModel.class, false)
.url("")
.id(37, "id", int.class)
.cache()
.build();
dataStoreFactory = mock(DataStoreFactory.class);
when(dataStoreFactory.dynamically(anyString(), any(Class.class)))
.thenReturn(mock(CloudStore.class));
when(dataStoreFactory.disk(Object.class)).thenReturn(mock(DiskStore.class));
when(dataStoreFactory.cloud(Object.class)).thenReturn(mock(CloudStore.class));
when(dataStoreFactory.disk(any())).thenReturn(mock(DiskStore.class));
when(dataStoreFactory.cloud(any())).thenReturn(mock(CloudStore.class));
when(dataStoreFactory.memory()).thenReturn(mock(MemoryStore.class));
dataService =
new DataService(
dataStoreFactory, AndroidSchedulers.mainThread(), mock(Scheduler.class));
Expand Down Expand Up @@ -110,12 +116,16 @@ public void getListOffLineFirst() throws Exception {
.disk(Object.class)
.dynamicGetList(anyString(), any(Class.class), anyBoolean(), anyBoolean()))
.thenReturn(Flowable.just(Collections.EMPTY_LIST));
when(dataStoreFactory
.memory()
.getAllItems(any(Class.class)))
.thenReturn(Single.just(Collections.singletonList(true)));

dataService.getListOffLineFirst(getRequest);

verify(dataStoreFactory.cloud(Object.class), times(1))
.dynamicGetList(anyString(), any(Class.class), anyBoolean(), anyBoolean());
verify(dataStoreFactory.disk(Object.class), times(0))
verify(dataStoreFactory.disk(Object.class), times(1))
.dynamicGetList(anyString(), any(Class.class), anyBoolean(), anyBoolean());
}

Expand Down Expand Up @@ -143,6 +153,11 @@ public void getObjectOffLineFirst() throws Exception {
anyBoolean()))
.thenReturn(flowable);

when(dataStoreFactory
.memory()
.getItem(anyString(), any(Class.class)))
.thenReturn(Single.just(true));

dataService.getObjectOffLineFirst(getRequest);

verify(dataStoreFactory.cloud(Object.class), times(1))
Expand All @@ -154,7 +169,7 @@ public void getObjectOffLineFirst() throws Exception {
any(Class.class),
anyBoolean(),
anyBoolean());
verify(dataStoreFactory.disk(Object.class), times(0))
verify(dataStoreFactory.disk(Object.class), times(1))
.dynamicGetObject(
anyString(),
anyString(),
Expand Down
Loading

0 comments on commit a1b4792

Please sign in to comment.