From 18cfff71f9f738324e78227ce7dda23ec2812225 Mon Sep 17 00:00:00 2001 From: johannes orgis Date: Tue, 19 Jan 2016 12:36:42 +0100 Subject: [PATCH 1/5] add leakcanary to detect and show the leak of the presenter (and everything it has references to) steps to reproduce: 1. deploy and start on device/emulator with no data network but with connection (so the REST connection times out) 2. put application to background while the REST call is waiting for the server response 3. click on leakcanary notification --- buildsystem/dependencies.gradle | 141 +++++++++--------- presentation/build.gradle | 1 + .../presentation/AndroidApplication.java | 29 ++-- 3 files changed, 90 insertions(+), 81 deletions(-) diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index 7ce44705..c14302db 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -1,82 +1,87 @@ allprojects { - repositories { - jcenter() - } + repositories { + jcenter() + } } ext { - //Android - androidBuildToolsVersion = "23.0.1" - androidMinSdkVersion = 15 - androidTargetSdkVersion = 21 - androidCompileSdkVersion = 21 + //Android + androidBuildToolsVersion = "23.0.1" + androidMinSdkVersion = 15 + androidTargetSdkVersion = 21 + androidCompileSdkVersion = 21 - //Libraries - daggerVersion = '2.0.2' - butterKnifeVersion = '7.0.1' - recyclerViewVersion = '21.0.3' - rxJavaVersion = '1.0.14' - rxAndroidVersion = '1.0.1' - javaxAnnotationVersion = '1.0' - gsonVersion = '2.3' - okHttpVersion = '2.5.0' - androidAnnotationsVersion = '21.0.3' + //Libraries + daggerVersion = '2.0.2' + butterKnifeVersion = '7.0.1' + recyclerViewVersion = '21.0.3' + rxJavaVersion = '1.0.14' + rxAndroidVersion = '1.0.1' + javaxAnnotationVersion = '1.0' + gsonVersion = '2.3' + okHttpVersion = '2.5.0' + androidAnnotationsVersion = '21.0.3' - //Testing - robolectricVersion = '3.0' - jUnitVersion = '4.12' - assertJVersion = '1.7.1' - mockitoVersion = '1.9.5' - dexmakerVersion = '1.0' - espressoVersion = '2.0' - testingSupportLibVersion = '0.1' + //Testing + robolectricVersion = '3.0' + jUnitVersion = '4.12' + assertJVersion = '1.7.1' + mockitoVersion = '1.9.5' + dexmakerVersion = '1.0' + espressoVersion = '2.0' + testingSupportLibVersion = '0.1' + //LeakCanary + leakCanaryVersion = '1.3.1' - presentationDependencies = [ - daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}", - dagger: "com.google.dagger:dagger:${daggerVersion}", - butterKnife: "com.jakewharton:butterknife:${butterKnifeVersion}", - recyclerView: "com.android.support:recyclerview-v7:${recyclerViewVersion}", - rxJava: "io.reactivex:rxjava:${rxJavaVersion}", - rxAndroid: "io.reactivex:rxandroid:${rxAndroidVersion}", - javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}", - ] - presentationTestDependencies = [ - mockito: "org.mockito:mockito-core:${mockitoVersion}", - dexmaker: "com.google.dexmaker:dexmaker:${dexmakerVersion}", - dexmakerMockito: "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}", - espresso: "com.android.support.test.espresso:espresso-core:${espressoVersion}", - testingSupportLib: "com.android.support.test:testing-support-lib:${testingSupportLibVersion}", - ] - domainDependencies = [ - daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}", - dagger: "com.google.dagger:dagger:${daggerVersion}", - javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}", - rxJava: "io.reactivex:rxjava:${rxJavaVersion}", - ] + presentationDependencies = [ + daggerCompiler : "com.google.dagger:dagger-compiler:${daggerVersion}", + dagger : "com.google.dagger:dagger:${daggerVersion}", + butterKnife : "com.jakewharton:butterknife:${butterKnifeVersion}", + recyclerView : "com.android.support:recyclerview-v7:${recyclerViewVersion}", + rxJava : "io.reactivex:rxjava:${rxJavaVersion}", + rxAndroid : "io.reactivex:rxandroid:${rxAndroidVersion}", + javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}", + leakCanary : "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}", + ] - domainTestDependencies = [ - junit: "junit:junit:${jUnitVersion}", - mockito: "org.mockito:mockito-core:${mockitoVersion}", - ] + presentationTestDependencies = [ + mockito : "org.mockito:mockito-core:${mockitoVersion}", + dexmaker : "com.google.dexmaker:dexmaker:${dexmakerVersion}", + dexmakerMockito : "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}", + espresso : "com.android.support.test.espresso:espresso-core:${espressoVersion}", + testingSupportLib: "com.android.support.test:testing-support-lib:${testingSupportLibVersion}", + ] - dataDependencies = [ - daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}", - dagger: "com.google.dagger:dagger:${daggerVersion}", - okHttp: "com.squareup.okhttp:okhttp:${okHttpVersion}", - gson: "com.google.code.gson:gson:${gsonVersion}", - rxJava: "io.reactivex:rxjava:${rxJavaVersion}", - rxAndroid: "io.reactivex:rxandroid:${rxAndroidVersion}", - javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}", - androidAnnotations: "com.android.support:support-annotations:${androidAnnotationsVersion}" - ] + domainDependencies = [ + daggerCompiler : "com.google.dagger:dagger-compiler:${daggerVersion}", + dagger : "com.google.dagger:dagger:${daggerVersion}", + javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}", + rxJava : "io.reactivex:rxjava:${rxJavaVersion}", + ] - dataTestDependencies = [ - junit: "junit:junit:${jUnitVersion}", - assertj: "org.assertj:assertj-core:${assertJVersion}", - mockito: "org.mockito:mockito-core:${mockitoVersion}", - robolectric: "org.robolectric:robolectric:${robolectricVersion}", - ] + domainTestDependencies = [ + junit : "junit:junit:${jUnitVersion}", + mockito: "org.mockito:mockito-core:${mockitoVersion}", + ] + + dataDependencies = [ + daggerCompiler : "com.google.dagger:dagger-compiler:${daggerVersion}", + dagger : "com.google.dagger:dagger:${daggerVersion}", + okHttp : "com.squareup.okhttp:okhttp:${okHttpVersion}", + gson : "com.google.code.gson:gson:${gsonVersion}", + rxJava : "io.reactivex:rxjava:${rxJavaVersion}", + rxAndroid : "io.reactivex:rxandroid:${rxAndroidVersion}", + javaxAnnotation : "javax.annotation:jsr250-api:${javaxAnnotationVersion}", + androidAnnotations: "com.android.support:support-annotations:${androidAnnotationsVersion}" + ] + + dataTestDependencies = [ + junit : "junit:junit:${jUnitVersion}", + assertj : "org.assertj:assertj-core:${assertJVersion}", + mockito : "org.mockito:mockito-core:${mockitoVersion}", + robolectric: "org.robolectric:robolectric:${robolectricVersion}", + ] } diff --git a/presentation/build.gradle b/presentation/build.gradle index 5c256f46..16e4defb 100644 --- a/presentation/build.gradle +++ b/presentation/build.gradle @@ -71,6 +71,7 @@ dependencies { compile presentationDependencies.recyclerView compile presentationDependencies.rxJava compile presentationDependencies.rxAndroid + compile presentationDependencies.leakCanary provided presentationDependencies.javaxAnnotation androidTestCompile presentationTestDependencies.mockito diff --git a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/AndroidApplication.java b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/AndroidApplication.java index d8cdb4eb..5d99fa31 100644 --- a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/AndroidApplication.java +++ b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/AndroidApplication.java @@ -16,29 +16,32 @@ package com.fernandocejas.android10.sample.presentation; import android.app.Application; + import com.fernandocejas.android10.sample.presentation.internal.di.components.ApplicationComponent; import com.fernandocejas.android10.sample.presentation.internal.di.components.DaggerApplicationComponent; import com.fernandocejas.android10.sample.presentation.internal.di.modules.ApplicationModule; +import com.squareup.leakcanary.LeakCanary; /** * Android Main Application */ public class AndroidApplication extends Application { - private ApplicationComponent applicationComponent; + private ApplicationComponent applicationComponent; - @Override public void onCreate() { - super.onCreate(); - this.initializeInjector(); - } + @Override public void onCreate() { + super.onCreate(); + this.initializeInjector(); + LeakCanary.install(this); + } - private void initializeInjector() { - this.applicationComponent = DaggerApplicationComponent.builder() - .applicationModule(new ApplicationModule(this)) - .build(); - } + private void initializeInjector() { + this.applicationComponent = DaggerApplicationComponent.builder() + .applicationModule(new ApplicationModule(this)) + .build(); + } - public ApplicationComponent getApplicationComponent() { - return this.applicationComponent; - } + public ApplicationComponent getApplicationComponent() { + return this.applicationComponent; + } } From 38e0bb73db6fb7286ea5f2ef2b352b8053fd46d1 Mon Sep 17 00:00:00 2001 From: johannes orgis Date: Tue, 19 Jan 2016 12:38:47 +0100 Subject: [PATCH 2/5] decorator class which wraps a subscription and nulls the reference on unsibscribe. As unsubscribe() is final in rx.Subscription.class we have to register an subscription as callback. --- .../presentation/SubscriptionDecorator.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 presentation/src/main/java/com/fernandocejas/android10/sample/presentation/SubscriptionDecorator.java diff --git a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/SubscriptionDecorator.java b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/SubscriptionDecorator.java new file mode 100644 index 00000000..433e7855 --- /dev/null +++ b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/SubscriptionDecorator.java @@ -0,0 +1,61 @@ +package com.fernandocejas.android10.sample.presentation; + +import android.support.annotation.NonNull; + +import rx.Subscriber; +import rx.Subscription; + +/** + * Created by jorgis on 1/19/16. + */ +public class SubscriptionDecorator extends Subscriber { + private Subscriber subscriber; + + public SubscriptionDecorator(Subscriber subscriber) { + this.subscriber = subscriber; + this.add(new DisposingSubscription(this)); + } + + @Override public void onCompleted() { + if (subscriber != null) { + subscriber.onCompleted(); + } + } + + @Override public void onError(Throwable e) { + if (subscriber != null) { + subscriber.onError(e); + } + } + + @Override public void onNext(T o) { + if (subscriber != null) { + subscriber.onNext(o); + } + } + + public void disposeDependencies() { + subscriber = null; + } + + private static class DisposingSubscription implements Subscription { + + private final SubscriptionDecorator callback; + private boolean unsubscribed; + + private DisposingSubscription(@NonNull SubscriptionDecorator callback) { + this.callback = callback; + } + + @Override public void unsubscribe() { + callback.disposeDependencies(); + unsubscribed = true; + } + + @Override public boolean isUnsubscribed() { + return unsubscribed; + } + } + + +} From e0377a2a6195f015b53f791e114b5b9efec3409f Mon Sep 17 00:00:00 2001 From: johannes orgis Date: Tue, 19 Jan 2016 12:39:35 +0100 Subject: [PATCH 3/5] wrap the subscriptions with the decorator before subscribing (sorry for the formatter changes) --- .../presenter/UserDetailsPresenter.java | 183 +++++++++--------- .../presenter/UserListPresenter.java | 155 ++++++++------- 2 files changed, 175 insertions(+), 163 deletions(-) diff --git a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java index 6c09e4ab..ad8a2693 100644 --- a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java +++ b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java @@ -15,20 +15,23 @@ */ package com.fernandocejas.android10.sample.presentation.presenter; +import javax.inject.Inject; +import javax.inject.Named; + import android.support.annotation.NonNull; + import com.fernandocejas.android10.sample.domain.User; import com.fernandocejas.android10.sample.domain.exception.DefaultErrorBundle; import com.fernandocejas.android10.sample.domain.exception.ErrorBundle; import com.fernandocejas.android10.sample.domain.interactor.DefaultSubscriber; import com.fernandocejas.android10.sample.domain.interactor.UseCase; +import com.fernandocejas.android10.sample.presentation.SubscriptionDecorator; import com.fernandocejas.android10.sample.presentation.exception.ErrorMessageFactory; import com.fernandocejas.android10.sample.presentation.internal.di.PerActivity; import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper; import com.fernandocejas.android10.sample.presentation.model.UserModel; import com.fernandocejas.android10.sample.presentation.view.UserDetailsView; import com.fernandocejas.frodo.annotation.RxLogSubscriber; -import javax.inject.Inject; -import javax.inject.Named; /** * {@link Presenter} that controls communication between views and models of the presentation @@ -37,96 +40,98 @@ @PerActivity public class UserDetailsPresenter implements Presenter { - /** id used to retrieve user details */ - private int userId; - - private UserDetailsView viewDetailsView; - - private final UseCase getUserDetailsUseCase; - private final UserModelDataMapper userModelDataMapper; - - @Inject - public UserDetailsPresenter(@Named("userDetails") UseCase getUserDetailsUseCase, - UserModelDataMapper userModelDataMapper) { - this.getUserDetailsUseCase = getUserDetailsUseCase; - this.userModelDataMapper = userModelDataMapper; - } - - public void setView(@NonNull UserDetailsView view) { - this.viewDetailsView = view; - } - - @Override public void resume() {} - - @Override public void pause() {} - - @Override public void destroy() { - this.getUserDetailsUseCase.unsubscribe(); - } - - /** - * Initializes the presenter by start retrieving user details. - */ - public void initialize(int userId) { - this.userId = userId; - this.loadUserDetails(); - } - - /** - * Loads user details. - */ - private void loadUserDetails() { - this.hideViewRetry(); - this.showViewLoading(); - this.getUserDetails(); - } - - private void showViewLoading() { - this.viewDetailsView.showLoading(); - } - - private void hideViewLoading() { - this.viewDetailsView.hideLoading(); - } - - private void showViewRetry() { - this.viewDetailsView.showRetry(); - } - - private void hideViewRetry() { - this.viewDetailsView.hideRetry(); - } - - private void showErrorMessage(ErrorBundle errorBundle) { - String errorMessage = ErrorMessageFactory.create(this.viewDetailsView.getContext(), - errorBundle.getException()); - this.viewDetailsView.showError(errorMessage); - } - - private void showUserDetailsInView(User user) { - final UserModel userModel = this.userModelDataMapper.transform(user); - this.viewDetailsView.renderUser(userModel); - } - - private void getUserDetails() { - this.getUserDetailsUseCase.execute(new UserDetailsSubscriber()); - } - - @RxLogSubscriber - private final class UserDetailsSubscriber extends DefaultSubscriber { - - @Override public void onCompleted() { - UserDetailsPresenter.this.hideViewLoading(); + /** id used to retrieve user details */ + private int userId; + + private UserDetailsView viewDetailsView; + + private final UseCase getUserDetailsUseCase; + private final UserModelDataMapper userModelDataMapper; + + @Inject + public UserDetailsPresenter(@Named("userDetails") UseCase getUserDetailsUseCase, + UserModelDataMapper userModelDataMapper) { + this.getUserDetailsUseCase = getUserDetailsUseCase; + this.userModelDataMapper = userModelDataMapper; + } + + public void setView(@NonNull UserDetailsView view) { + this.viewDetailsView = view; + } + + @Override public void resume() { + } + + @Override public void pause() { + } + + @Override public void destroy() { + this.getUserDetailsUseCase.unsubscribe(); + } + + /** + * Initializes the presenter by start retrieving user details. + */ + public void initialize(int userId) { + this.userId = userId; + this.loadUserDetails(); + } + + /** + * Loads user details. + */ + private void loadUserDetails() { + this.hideViewRetry(); + this.showViewLoading(); + this.getUserDetails(); + } + + private void showViewLoading() { + this.viewDetailsView.showLoading(); + } + + private void hideViewLoading() { + this.viewDetailsView.hideLoading(); + } + + private void showViewRetry() { + this.viewDetailsView.showRetry(); } - @Override public void onError(Throwable e) { - UserDetailsPresenter.this.hideViewLoading(); - UserDetailsPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e)); - UserDetailsPresenter.this.showViewRetry(); + private void hideViewRetry() { + this.viewDetailsView.hideRetry(); } - @Override public void onNext(User user) { - UserDetailsPresenter.this.showUserDetailsInView(user); + private void showErrorMessage(ErrorBundle errorBundle) { + String errorMessage = ErrorMessageFactory.create(this.viewDetailsView.getContext(), + errorBundle.getException()); + this.viewDetailsView.showError(errorMessage); + } + + private void showUserDetailsInView(User user) { + final UserModel userModel = this.userModelDataMapper.transform(user); + this.viewDetailsView.renderUser(userModel); + } + + private void getUserDetails() { + this.getUserDetailsUseCase.execute(new SubscriptionDecorator<>(new UserDetailsSubscriber())); + } + + @RxLogSubscriber + private final class UserDetailsSubscriber extends DefaultSubscriber { + + @Override public void onCompleted() { + UserDetailsPresenter.this.hideViewLoading(); + } + + @Override public void onError(Throwable e) { + UserDetailsPresenter.this.hideViewLoading(); + UserDetailsPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e)); + UserDetailsPresenter.this.showViewRetry(); + } + + @Override public void onNext(User user) { + UserDetailsPresenter.this.showUserDetailsInView(user); + } } - } } diff --git a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java index 75ab5866..e9c7e32a 100644 --- a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java +++ b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java @@ -15,7 +15,14 @@ */ package com.fernandocejas.android10.sample.presentation.presenter; +import javax.inject.Inject; +import javax.inject.Named; + +import java.util.Collection; +import java.util.List; + import android.support.annotation.NonNull; + import com.fernandocejas.android10.sample.domain.User; import com.fernandocejas.android10.sample.domain.exception.DefaultErrorBundle; import com.fernandocejas.android10.sample.domain.exception.ErrorBundle; @@ -25,11 +32,8 @@ import com.fernandocejas.android10.sample.presentation.internal.di.PerActivity; import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper; import com.fernandocejas.android10.sample.presentation.model.UserModel; +import com.fernandocejas.android10.sample.presentation.SubscriptionDecorator; import com.fernandocejas.android10.sample.presentation.view.UserListView; -import java.util.Collection; -import java.util.List; -import javax.inject.Inject; -import javax.inject.Named; /** * {@link Presenter} that controls communication between views and models of the presentation @@ -38,95 +42,98 @@ @PerActivity public class UserListPresenter implements Presenter { - private UserListView viewListView; + private UserListView viewListView; - private final UseCase getUserListUseCase; - private final UserModelDataMapper userModelDataMapper; + private final UseCase getUserListUseCase; + private final UserModelDataMapper userModelDataMapper; - @Inject - public UserListPresenter(@Named("userList") UseCase getUserListUserCase, UserModelDataMapper userModelDataMapper) { - this.getUserListUseCase = getUserListUserCase; - this.userModelDataMapper = userModelDataMapper; - } + @Inject + public UserListPresenter(@Named("userList") UseCase getUserListUserCase, UserModelDataMapper + userModelDataMapper) { + this.getUserListUseCase = getUserListUserCase; + this.userModelDataMapper = userModelDataMapper; + } - public void setView(@NonNull UserListView view) { - this.viewListView = view; - } + public void setView(@NonNull UserListView view) { + this.viewListView = view; + } - @Override public void resume() {} + @Override public void resume() { + } - @Override public void pause() {} + @Override public void pause() { + } - @Override public void destroy() { - this.getUserListUseCase.unsubscribe(); - } + @Override public void destroy() { + this.getUserListUseCase.unsubscribe(); + } - /** - * Initializes the presenter by start retrieving the user list. - */ - public void initialize() { - this.loadUserList(); - } + /** + * Initializes the presenter by start retrieving the user list. + */ + public void initialize() { + this.loadUserList(); + } - /** - * Loads all users. - */ - private void loadUserList() { - this.hideViewRetry(); - this.showViewLoading(); - this.getUserList(); - } + /** + * Loads all users. + */ + private void loadUserList() { + this.hideViewRetry(); + this.showViewLoading(); + this.getUserList(); + } - public void onUserClicked(UserModel userModel) { - this.viewListView.viewUser(userModel); - } + public void onUserClicked(UserModel userModel) { + this.viewListView.viewUser(userModel); + } - private void showViewLoading() { - this.viewListView.showLoading(); - } + private void showViewLoading() { + this.viewListView.showLoading(); + } - private void hideViewLoading() { - this.viewListView.hideLoading(); - } + private void hideViewLoading() { + this.viewListView.hideLoading(); + } - private void showViewRetry() { - this.viewListView.showRetry(); - } + private void showViewRetry() { + this.viewListView.showRetry(); + } - private void hideViewRetry() { - this.viewListView.hideRetry(); - } + private void hideViewRetry() { + this.viewListView.hideRetry(); + } - private void showErrorMessage(ErrorBundle errorBundle) { - String errorMessage = ErrorMessageFactory.create(this.viewListView.getContext(), - errorBundle.getException()); - this.viewListView.showError(errorMessage); - } + private void showErrorMessage(ErrorBundle errorBundle) { + String errorMessage = ErrorMessageFactory.create(this.viewListView.getContext(), + errorBundle.getException()); + this.viewListView.showError(errorMessage); + } - private void showUsersCollectionInView(Collection usersCollection) { - final Collection userModelsCollection = - this.userModelDataMapper.transform(usersCollection); - this.viewListView.renderUserList(userModelsCollection); - } + private void showUsersCollectionInView(Collection usersCollection) { + final Collection userModelsCollection = + this.userModelDataMapper.transform(usersCollection); + this.viewListView.renderUserList(userModelsCollection); + } - private void getUserList() { - this.getUserListUseCase.execute(new UserListSubscriber()); - } + private void getUserList() { + this.getUserListUseCase.execute(new SubscriptionDecorator<>(new UserListSubscriber())); + } - private final class UserListSubscriber extends DefaultSubscriber> { + private final class UserListSubscriber extends DefaultSubscriber> { - @Override public void onCompleted() { - UserListPresenter.this.hideViewLoading(); - } + @Override public void onCompleted() { + UserListPresenter.this.hideViewLoading(); + } - @Override public void onError(Throwable e) { - UserListPresenter.this.hideViewLoading(); - UserListPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e)); - UserListPresenter.this.showViewRetry(); - } + @Override public void onError(Throwable e) { + UserListPresenter.this.hideViewLoading(); + UserListPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e)); + UserListPresenter.this.showViewRetry(); + } - @Override public void onNext(List users) { - UserListPresenter.this.showUsersCollectionInView(users); + @Override public void onNext(List users) { + UserListPresenter.this.showUsersCollectionInView(users); + } } - } } From 3d215f8bb6d81fc5b6222ad7a13a9f3b66a4e446 Mon Sep 17 00:00:00 2001 From: johannes orgis Date: Tue, 19 Jan 2016 14:04:36 +0100 Subject: [PATCH 4/5] applying square-android codestyle --- .../presentation/SubscriptionDecorator.java | 69 +++---- .../presenter/UserDetailsPresenter.java | 189 +++++++++--------- .../presenter/UserListPresenter.java | 163 ++++++++------- 3 files changed, 204 insertions(+), 217 deletions(-) diff --git a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/SubscriptionDecorator.java b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/SubscriptionDecorator.java index 433e7855..e0118fe3 100644 --- a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/SubscriptionDecorator.java +++ b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/SubscriptionDecorator.java @@ -1,7 +1,6 @@ package com.fernandocejas.android10.sample.presentation; import android.support.annotation.NonNull; - import rx.Subscriber; import rx.Subscription; @@ -9,53 +8,51 @@ * Created by jorgis on 1/19/16. */ public class SubscriptionDecorator extends Subscriber { - private Subscriber subscriber; - - public SubscriptionDecorator(Subscriber subscriber) { - this.subscriber = subscriber; - this.add(new DisposingSubscription(this)); - } + private Subscriber subscriber; - @Override public void onCompleted() { - if (subscriber != null) { - subscriber.onCompleted(); - } - } + public SubscriptionDecorator(Subscriber subscriber) { + this.subscriber = subscriber; + this.add(new DisposingSubscription(this)); + } - @Override public void onError(Throwable e) { - if (subscriber != null) { - subscriber.onError(e); - } + @Override public void onCompleted() { + if (subscriber != null) { + subscriber.onCompleted(); } + } - @Override public void onNext(T o) { - if (subscriber != null) { - subscriber.onNext(o); - } + @Override public void onError(Throwable e) { + if (subscriber != null) { + subscriber.onError(e); } + } - public void disposeDependencies() { - subscriber = null; + @Override public void onNext(T o) { + if (subscriber != null) { + subscriber.onNext(o); } + } - private static class DisposingSubscription implements Subscription { + public void disposeDependencies() { + subscriber = null; + } - private final SubscriptionDecorator callback; - private boolean unsubscribed; + private static class DisposingSubscription implements Subscription { - private DisposingSubscription(@NonNull SubscriptionDecorator callback) { - this.callback = callback; - } + private final SubscriptionDecorator callback; + private boolean unsubscribed; - @Override public void unsubscribe() { - callback.disposeDependencies(); - unsubscribed = true; - } - - @Override public boolean isUnsubscribed() { - return unsubscribed; - } + private DisposingSubscription(@NonNull SubscriptionDecorator callback) { + this.callback = callback; } + @Override public void unsubscribe() { + callback.disposeDependencies(); + unsubscribed = true; + } + @Override public boolean isUnsubscribed() { + return unsubscribed; + } + } } diff --git a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java index ad8a2693..dc0181cb 100644 --- a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java +++ b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserDetailsPresenter.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,11 +15,7 @@ */ package com.fernandocejas.android10.sample.presentation.presenter; -import javax.inject.Inject; -import javax.inject.Named; - import android.support.annotation.NonNull; - import com.fernandocejas.android10.sample.domain.User; import com.fernandocejas.android10.sample.domain.exception.DefaultErrorBundle; import com.fernandocejas.android10.sample.domain.exception.ErrorBundle; @@ -32,106 +28,105 @@ import com.fernandocejas.android10.sample.presentation.model.UserModel; import com.fernandocejas.android10.sample.presentation.view.UserDetailsView; import com.fernandocejas.frodo.annotation.RxLogSubscriber; +import javax.inject.Inject; +import javax.inject.Named; /** * {@link Presenter} that controls communication between views and models of the presentation * layer. */ -@PerActivity -public class UserDetailsPresenter implements Presenter { - - /** id used to retrieve user details */ - private int userId; - - private UserDetailsView viewDetailsView; - - private final UseCase getUserDetailsUseCase; - private final UserModelDataMapper userModelDataMapper; - - @Inject - public UserDetailsPresenter(@Named("userDetails") UseCase getUserDetailsUseCase, - UserModelDataMapper userModelDataMapper) { - this.getUserDetailsUseCase = getUserDetailsUseCase; - this.userModelDataMapper = userModelDataMapper; +@PerActivity public class UserDetailsPresenter implements Presenter { + + /** id used to retrieve user details */ + private int userId; + + private UserDetailsView viewDetailsView; + + private final UseCase getUserDetailsUseCase; + private final UserModelDataMapper userModelDataMapper; + + @Inject public UserDetailsPresenter(@Named("userDetails") UseCase getUserDetailsUseCase, + UserModelDataMapper userModelDataMapper) { + this.getUserDetailsUseCase = getUserDetailsUseCase; + this.userModelDataMapper = userModelDataMapper; + } + + public void setView(@NonNull UserDetailsView view) { + this.viewDetailsView = view; + } + + @Override public void resume() { + } + + @Override public void pause() { + } + + @Override public void destroy() { + this.getUserDetailsUseCase.unsubscribe(); + } + + /** + * Initializes the presenter by start retrieving user details. + */ + public void initialize(int userId) { + this.userId = userId; + this.loadUserDetails(); + } + + /** + * Loads user details. + */ + private void loadUserDetails() { + this.hideViewRetry(); + this.showViewLoading(); + this.getUserDetails(); + } + + private void showViewLoading() { + this.viewDetailsView.showLoading(); + } + + private void hideViewLoading() { + this.viewDetailsView.hideLoading(); + } + + private void showViewRetry() { + this.viewDetailsView.showRetry(); + } + + private void hideViewRetry() { + this.viewDetailsView.hideRetry(); + } + + private void showErrorMessage(ErrorBundle errorBundle) { + String errorMessage = + ErrorMessageFactory.create(this.viewDetailsView.getContext(), errorBundle.getException()); + this.viewDetailsView.showError(errorMessage); + } + + private void showUserDetailsInView(User user) { + final UserModel userModel = this.userModelDataMapper.transform(user); + this.viewDetailsView.renderUser(userModel); + } + + private void getUserDetails() { + this.getUserDetailsUseCase.execute(new SubscriptionDecorator<>(new UserDetailsSubscriber())); + } + + @RxLogSubscriber private final class UserDetailsSubscriber extends DefaultSubscriber { + + @Override public void onCompleted() { + UserDetailsPresenter.this.hideViewLoading(); } - public void setView(@NonNull UserDetailsView view) { - this.viewDetailsView = view; + @Override public void onError(Throwable e) { + UserDetailsPresenter.this.hideViewLoading(); + UserDetailsPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e)); + UserDetailsPresenter.this.showViewRetry(); } - @Override public void resume() { - } - - @Override public void pause() { - } - - @Override public void destroy() { - this.getUserDetailsUseCase.unsubscribe(); - } - - /** - * Initializes the presenter by start retrieving user details. - */ - public void initialize(int userId) { - this.userId = userId; - this.loadUserDetails(); - } - - /** - * Loads user details. - */ - private void loadUserDetails() { - this.hideViewRetry(); - this.showViewLoading(); - this.getUserDetails(); - } - - private void showViewLoading() { - this.viewDetailsView.showLoading(); - } - - private void hideViewLoading() { - this.viewDetailsView.hideLoading(); - } - - private void showViewRetry() { - this.viewDetailsView.showRetry(); - } - - private void hideViewRetry() { - this.viewDetailsView.hideRetry(); - } - - private void showErrorMessage(ErrorBundle errorBundle) { - String errorMessage = ErrorMessageFactory.create(this.viewDetailsView.getContext(), - errorBundle.getException()); - this.viewDetailsView.showError(errorMessage); - } - - private void showUserDetailsInView(User user) { - final UserModel userModel = this.userModelDataMapper.transform(user); - this.viewDetailsView.renderUser(userModel); - } - - private void getUserDetails() { - this.getUserDetailsUseCase.execute(new SubscriptionDecorator<>(new UserDetailsSubscriber())); - } - - @RxLogSubscriber - private final class UserDetailsSubscriber extends DefaultSubscriber { - - @Override public void onCompleted() { - UserDetailsPresenter.this.hideViewLoading(); - } - - @Override public void onError(Throwable e) { - UserDetailsPresenter.this.hideViewLoading(); - UserDetailsPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e)); - UserDetailsPresenter.this.showViewRetry(); - } - - @Override public void onNext(User user) { - UserDetailsPresenter.this.showUserDetailsInView(user); - } + @Override public void onNext(User user) { + UserDetailsPresenter.this.showUserDetailsInView(user); } + } } diff --git a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java index e9c7e32a..02410600 100644 --- a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java +++ b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/presenter/UserListPresenter.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -15,125 +15,120 @@ */ package com.fernandocejas.android10.sample.presentation.presenter; -import javax.inject.Inject; -import javax.inject.Named; - -import java.util.Collection; -import java.util.List; - import android.support.annotation.NonNull; - import com.fernandocejas.android10.sample.domain.User; import com.fernandocejas.android10.sample.domain.exception.DefaultErrorBundle; import com.fernandocejas.android10.sample.domain.exception.ErrorBundle; import com.fernandocejas.android10.sample.domain.interactor.DefaultSubscriber; import com.fernandocejas.android10.sample.domain.interactor.UseCase; +import com.fernandocejas.android10.sample.presentation.SubscriptionDecorator; import com.fernandocejas.android10.sample.presentation.exception.ErrorMessageFactory; import com.fernandocejas.android10.sample.presentation.internal.di.PerActivity; import com.fernandocejas.android10.sample.presentation.mapper.UserModelDataMapper; import com.fernandocejas.android10.sample.presentation.model.UserModel; -import com.fernandocejas.android10.sample.presentation.SubscriptionDecorator; import com.fernandocejas.android10.sample.presentation.view.UserListView; +import java.util.Collection; +import java.util.List; +import javax.inject.Inject; +import javax.inject.Named; /** * {@link Presenter} that controls communication between views and models of the presentation * layer. */ -@PerActivity -public class UserListPresenter implements Presenter { +@PerActivity public class UserListPresenter implements Presenter { - private UserListView viewListView; + private UserListView viewListView; - private final UseCase getUserListUseCase; - private final UserModelDataMapper userModelDataMapper; + private final UseCase getUserListUseCase; + private final UserModelDataMapper userModelDataMapper; - @Inject - public UserListPresenter(@Named("userList") UseCase getUserListUserCase, UserModelDataMapper - userModelDataMapper) { - this.getUserListUseCase = getUserListUserCase; - this.userModelDataMapper = userModelDataMapper; - } + @Inject public UserListPresenter(@Named("userList") UseCase getUserListUserCase, + UserModelDataMapper userModelDataMapper) { + this.getUserListUseCase = getUserListUserCase; + this.userModelDataMapper = userModelDataMapper; + } - public void setView(@NonNull UserListView view) { - this.viewListView = view; - } + public void setView(@NonNull UserListView view) { + this.viewListView = view; + } - @Override public void resume() { - } + @Override public void resume() { + } - @Override public void pause() { - } + @Override public void pause() { + } - @Override public void destroy() { - this.getUserListUseCase.unsubscribe(); - } + @Override public void destroy() { + this.getUserListUseCase.unsubscribe(); + } - /** - * Initializes the presenter by start retrieving the user list. - */ - public void initialize() { - this.loadUserList(); - } + /** + * Initializes the presenter by start retrieving the user list. + */ + public void initialize() { + this.loadUserList(); + } - /** - * Loads all users. - */ - private void loadUserList() { - this.hideViewRetry(); - this.showViewLoading(); - this.getUserList(); - } + /** + * Loads all users. + */ + private void loadUserList() { + this.hideViewRetry(); + this.showViewLoading(); + this.getUserList(); + } - public void onUserClicked(UserModel userModel) { - this.viewListView.viewUser(userModel); - } + public void onUserClicked(UserModel userModel) { + this.viewListView.viewUser(userModel); + } - private void showViewLoading() { - this.viewListView.showLoading(); - } + private void showViewLoading() { + this.viewListView.showLoading(); + } - private void hideViewLoading() { - this.viewListView.hideLoading(); - } + private void hideViewLoading() { + this.viewListView.hideLoading(); + } - private void showViewRetry() { - this.viewListView.showRetry(); - } + private void showViewRetry() { + this.viewListView.showRetry(); + } - private void hideViewRetry() { - this.viewListView.hideRetry(); - } + private void hideViewRetry() { + this.viewListView.hideRetry(); + } - private void showErrorMessage(ErrorBundle errorBundle) { - String errorMessage = ErrorMessageFactory.create(this.viewListView.getContext(), - errorBundle.getException()); - this.viewListView.showError(errorMessage); - } + private void showErrorMessage(ErrorBundle errorBundle) { + String errorMessage = + ErrorMessageFactory.create(this.viewListView.getContext(), errorBundle.getException()); + this.viewListView.showError(errorMessage); + } - private void showUsersCollectionInView(Collection usersCollection) { - final Collection userModelsCollection = - this.userModelDataMapper.transform(usersCollection); - this.viewListView.renderUserList(userModelsCollection); - } + private void showUsersCollectionInView(Collection usersCollection) { + final Collection userModelsCollection = + this.userModelDataMapper.transform(usersCollection); + this.viewListView.renderUserList(userModelsCollection); + } - private void getUserList() { - this.getUserListUseCase.execute(new SubscriptionDecorator<>(new UserListSubscriber())); - } + private void getUserList() { + this.getUserListUseCase.execute(new SubscriptionDecorator<>(new UserListSubscriber())); + } - private final class UserListSubscriber extends DefaultSubscriber> { + private final class UserListSubscriber extends DefaultSubscriber> { - @Override public void onCompleted() { - UserListPresenter.this.hideViewLoading(); - } + @Override public void onCompleted() { + UserListPresenter.this.hideViewLoading(); + } - @Override public void onError(Throwable e) { - UserListPresenter.this.hideViewLoading(); - UserListPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e)); - UserListPresenter.this.showViewRetry(); - } + @Override public void onError(Throwable e) { + UserListPresenter.this.hideViewLoading(); + UserListPresenter.this.showErrorMessage(new DefaultErrorBundle((Exception) e)); + UserListPresenter.this.showViewRetry(); + } - @Override public void onNext(List users) { - UserListPresenter.this.showUsersCollectionInView(users); - } + @Override public void onNext(List users) { + UserListPresenter.this.showUsersCollectionInView(users); } + } } From 97697d4a4d2a89e54c2ad9e4427db5c4930defa9 Mon Sep 17 00:00:00 2001 From: johannes orgis Date: Tue, 19 Jan 2016 14:07:35 +0100 Subject: [PATCH 5/5] codestyle --- .../presentation/AndroidApplication.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/AndroidApplication.java b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/AndroidApplication.java index 5d99fa31..38a7ab62 100644 --- a/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/AndroidApplication.java +++ b/presentation/src/main/java/com/fernandocejas/android10/sample/presentation/AndroidApplication.java @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -16,7 +16,6 @@ package com.fernandocejas.android10.sample.presentation; import android.app.Application; - import com.fernandocejas.android10.sample.presentation.internal.di.components.ApplicationComponent; import com.fernandocejas.android10.sample.presentation.internal.di.components.DaggerApplicationComponent; import com.fernandocejas.android10.sample.presentation.internal.di.modules.ApplicationModule; @@ -27,21 +26,20 @@ */ public class AndroidApplication extends Application { - private ApplicationComponent applicationComponent; + private ApplicationComponent applicationComponent; - @Override public void onCreate() { - super.onCreate(); - this.initializeInjector(); - LeakCanary.install(this); - } + @Override public void onCreate() { + super.onCreate(); + this.initializeInjector(); + LeakCanary.install(this); + } - private void initializeInjector() { - this.applicationComponent = DaggerApplicationComponent.builder() - .applicationModule(new ApplicationModule(this)) - .build(); - } + private void initializeInjector() { + this.applicationComponent = + DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build(); + } - public ApplicationComponent getApplicationComponent() { - return this.applicationComponent; - } + public ApplicationComponent getApplicationComponent() { + return this.applicationComponent; + } }