Skip to content

Commit afa2540

Browse files
- New architecture for MVP
1 parent df63fa9 commit afa2540

File tree

7 files changed

+215
-105
lines changed

7 files changed

+215
-105
lines changed

mvp/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ android {
2828
dependencies {
2929
implementation fileTree(dir: 'libs', include: ['*.jar'])
3030

31+
implementation project(':loggalitic')
32+
3133
implementation 'com.android.support:appcompat-v7:' + rootProject.supportLibraryVersion
3234
implementation 'com.squareup.retrofit2:retrofit:' + rootProject.retrofit
3335
implementation 'com.squareup.okhttp3:logging-interceptor:' + rootProject.okhttp
34-
implementation 'android.arch.lifecycle:viewmodel:' + rootProject.lifecycleVersion
36+
implementation 'android.arch.lifecycle:common-java8:' + rootProject.lifecycleVersion
3537
}
Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,71 @@
11
package com.android.oleksandrpriadko.mvp.presenter;
22

3-
public abstract class BasePresenter<T extends BasePresenter.PresenterView> {
3+
import android.arch.lifecycle.DefaultLifecycleObserver;
4+
import android.arch.lifecycle.Lifecycle;
5+
import android.arch.lifecycle.LifecycleOwner;
6+
import android.support.annotation.CallSuper;
7+
import android.support.annotation.NonNull;
8+
import android.support.annotation.Nullable;
9+
10+
import com.android.oleksandrpriadko.loggalitic.Loggalitic;
11+
12+
public abstract class BasePresenter<T> implements DefaultLifecycleObserver {
413

514
private T mView;
615

7-
protected final T getView() {
8-
return mView;
16+
private boolean mBound;
17+
18+
public BasePresenter(T view, @NonNull final LifecycleOwner lifecycleOwner) {
19+
if (view == null) {
20+
throw new NullPointerException("View should not be null");
21+
}
22+
if (lifecycleOwner.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
23+
logState("dead lifecycle owner");
24+
return;
25+
}
26+
logState("created");
27+
lifecycleOwner.getLifecycle().addObserver(this);
28+
mView = view;
29+
bind(true);
30+
}
31+
32+
@Override
33+
@CallSuper
34+
public void onResume(@NonNull LifecycleOwner owner) {
35+
logState("onResume");
36+
bind(true);
937
}
1038

11-
protected final boolean isViewAdded() {
12-
return mView != null;
39+
@Override
40+
public void onStop(@NonNull LifecycleOwner owner) {
41+
logState("onStop");
42+
bind(false);
1343
}
1444

15-
public final void bindView(T view) {
16-
this.mView = view;
45+
@Override
46+
public final void onDestroy(@NonNull LifecycleOwner owner) {
47+
logState("onDestroy");
48+
bind(false);
49+
mView = null;
50+
logState("view destroyed");
1751
}
1852

19-
public final void unBindView() {
20-
this.mView = null;
53+
protected final void bind(boolean bind) {
54+
mBound = bind;
55+
logState("bind " + bind);
2156
}
2257

23-
/* no-op */
24-
public interface PresenterView {}
58+
@Nullable
59+
protected final T getView() {
60+
return mBound ? mView : null;
61+
}
62+
63+
@NonNull
64+
protected final T getViewSafely() {
65+
return mView;
66+
}
67+
68+
private void logState(@NonNull final String message) {
69+
Loggalitic.logger().d(getClass().getSimpleName(), message);
70+
}
2571
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.android.oleksandrpriadko.mvp.repo;
2+
3+
import java.util.ArrayList;
4+
import java.util.Iterator;
5+
import java.util.List;
6+
7+
import android.arch.lifecycle.GenericLifecycleObserver;
8+
import android.arch.lifecycle.Lifecycle;
9+
import android.arch.lifecycle.LifecycleOwner;
10+
import android.support.annotation.CallSuper;
11+
import android.support.annotation.NonNull;
12+
import android.support.annotation.Nullable;
13+
14+
import com.android.oleksandrpriadko.loggalitic.Loggalitic;
15+
16+
import static android.arch.lifecycle.Lifecycle.State.DESTROYED;
17+
18+
public abstract class ObservableRepo {
19+
20+
private List<LifecycleBoundObserver> mLifecycleBoundObservers = new ArrayList<>();
21+
22+
ObservableRepo(@NonNull final LifecycleOwner lifecycleOwner) {
23+
requestObserve(lifecycleOwner);
24+
}
25+
26+
@CallSuper
27+
public void requestObserve(LifecycleOwner lifecycleOwner) {
28+
if (lifecycleOwner.getLifecycle().getCurrentState() == DESTROYED) {
29+
logState("dead lifecycle owner");
30+
return;
31+
}
32+
33+
if (isAlreadyAdded(lifecycleOwner)) {
34+
logState("already existing lifecycle owner");
35+
return;
36+
}
37+
38+
LifecycleBoundObserver lifecycleBoundObserver = new LifecycleBoundObserver(lifecycleOwner);
39+
mLifecycleBoundObservers.add(lifecycleBoundObserver);
40+
logState("added");
41+
}
42+
43+
private boolean isAlreadyAdded(@NonNull final LifecycleOwner incomingLifecycleOwner) {
44+
for (LifecycleBoundObserver lifecycleBoundObserver : mLifecycleBoundObservers) {
45+
if (lifecycleBoundObserver.getLifecycleOwner() != null
46+
&& lifecycleBoundObserver.getLifecycleOwner().equals(incomingLifecycleOwner)) {
47+
return true;
48+
}
49+
}
50+
return false;
51+
}
52+
53+
@Nullable
54+
private LifecycleBoundObserver findObserver(@NonNull final LifecycleOwner lifecycleOwner) {
55+
for (LifecycleBoundObserver lifecycleBoundObserver : mLifecycleBoundObservers) {
56+
if (lifecycleBoundObserver.getLifecycleOwner() != null) {
57+
if (lifecycleBoundObserver.getLifecycleOwner().equals(lifecycleOwner)) {
58+
return lifecycleBoundObserver;
59+
}
60+
}
61+
}
62+
return null;
63+
}
64+
65+
@CallSuper
66+
public void requestRemoveObserver(LifecycleOwner lifecycleOwner) {
67+
LifecycleBoundObserver lifecycleBoundObserver = findObserver(lifecycleOwner);
68+
if (lifecycleBoundObserver != null) {
69+
mLifecycleBoundObservers.remove(lifecycleBoundObserver);
70+
logState("removed");
71+
} else {
72+
logState("not found, nothing to remove");
73+
}
74+
75+
cleanUpObservers();
76+
if (!hasObservers()) {
77+
logState("no observers, destroy " + mLifecycleBoundObservers.size());
78+
cleanUp();
79+
}
80+
}
81+
82+
private void cleanUpObservers() {
83+
Iterator iterator = mLifecycleBoundObservers.iterator();
84+
while (iterator.hasNext()) {
85+
LifecycleBoundObserver lifecycleBoundObserver = (LifecycleBoundObserver) iterator.next();
86+
if (lifecycleBoundObserver == null || lifecycleBoundObserver.getLifecycleOwner() == null) {
87+
iterator.remove();
88+
logState("found nullable lifecycle owner during clean up");
89+
}
90+
}
91+
logState("observers cleaned up");
92+
}
93+
94+
public boolean hasObservers() {
95+
return !mLifecycleBoundObservers.isEmpty();
96+
}
97+
98+
public abstract void cleanUp();
99+
100+
private void logState(@NonNull final String message) {
101+
Loggalitic.logger().d(getClass().getSimpleName(), message);
102+
}
103+
104+
private final class LifecycleBoundObserver implements GenericLifecycleObserver {
105+
106+
private final LifecycleOwner mLifecycleOwner;
107+
108+
private LifecycleBoundObserver(@NonNull LifecycleOwner owner) {
109+
mLifecycleOwner = owner;
110+
mLifecycleOwner.getLifecycle().addObserver(this);
111+
}
112+
113+
@Override
114+
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
115+
logState("onStateChanged " + event.name() + " " + mLifecycleOwner);
116+
if (mLifecycleOwner.getLifecycle().getCurrentState() == DESTROYED) {
117+
mLifecycleOwner.getLifecycle().removeObserver(this);
118+
logState("dead lifecycle owner " + mLifecycleOwner);
119+
120+
requestRemoveObserver(mLifecycleOwner);
121+
}
122+
}
123+
124+
private LifecycleOwner getLifecycleOwner() {
125+
return mLifecycleOwner;
126+
}
127+
}
128+
129+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.android.oleksandrpriadko.mvp.repo_extension;
2+
3+
public interface RepoExtension {
4+
5+
void cleanUp();
6+
7+
}

mvp/src/main/java/com/android/oleksandrpriadko/mvp/interactor/RetrofitInteractor.java renamed to mvp/src/main/java/com/android/oleksandrpriadko/mvp/repo_extension/RetrofitRepoExtension.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.android.oleksandrpriadko.mvp.interactor;
1+
package com.android.oleksandrpriadko.mvp.repo_extension;
22

33
import android.support.annotation.NonNull;
44

@@ -8,13 +8,13 @@
88
import retrofit2.Converter;
99
import retrofit2.Retrofit;
1010

11-
public abstract class RetrofitInteractor {
11+
public abstract class RetrofitRepoExtension implements RepoExtension {
1212

13-
private final String baseUrl;
14-
private Retrofit retrofit;
13+
private final String mBaseUrl;
14+
private Retrofit mRetrofit;
1515

16-
public RetrofitInteractor(@NonNull final String baseUrl) {
17-
this.baseUrl = baseUrl;
16+
public RetrofitRepoExtension(@NonNull final String baseUrl) {
17+
this.mBaseUrl = baseUrl;
1818
this.initRetrofit();
1919
}
2020

@@ -35,30 +35,34 @@ private void initRetrofit() {
3535
}
3636

3737
OkHttpClient client = builder.build();
38-
String testUrl = getBaseUrl();
39-
this.retrofit = new Retrofit.Builder()
40-
.baseUrl(testUrl)
38+
this.mRetrofit = new Retrofit.Builder()
39+
.baseUrl(getBaseUrl())
4140
.client(client)
4241
.addConverterFactory(getConverterFactory())
4342
.build();
4443
}
4544

4645
private String getBaseUrl() {
47-
return this.baseUrl;
46+
return this.mBaseUrl;
4847
}
4948

5049
private Retrofit getRetrofit() {
51-
if (this.retrofit == null) {
50+
if (this.mRetrofit == null) {
5251
this.initRetrofit();
5352
}
54-
return this.retrofit;
53+
return this.mRetrofit;
5554
}
5655

57-
protected <A> A getApi(final Class<A> apiClass) {
56+
public <A> A getApi(final Class<A> apiClass) {
5857
return this.getRetrofit().create(apiClass);
5958
}
6059

61-
public interface ProcessListener {
60+
@Override
61+
public void cleanUp() {
62+
mRetrofit = null;
63+
}
64+
65+
public interface Listener {
6266

6367
void onLoadingStarted();
6468

@@ -67,4 +71,4 @@ public interface ProcessListener {
6771
void onLoadingError(@NonNull Throwable throwable);
6872

6973
}
70-
}
74+
}

mvp/src/main/java/com/android/oleksandrpriadko/mvp/viewmodel/BaseViewModel.java

Lines changed: 0 additions & 41 deletions
This file was deleted.

mvp/src/main/java/com/android/oleksandrpriadko/mvp/viewmodel/BaseViewModelFactory.java

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)