314 lines
15 KiB
Java
314 lines
15 KiB
Java
/*
|
|
* Copyright (c) 2016 Touch Instinct
|
|
*
|
|
* This file is part of RoboSwag library.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* 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
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
package ru.touchin.templates;
|
|
|
|
import android.app.Service;
|
|
import android.content.Intent;
|
|
import android.os.Handler;
|
|
import android.os.IBinder;
|
|
import android.support.annotation.NonNull;
|
|
|
|
import ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity;
|
|
import ru.touchin.roboswag.components.utils.Logic;
|
|
import ru.touchin.roboswag.components.utils.UiUtils;
|
|
import ru.touchin.roboswag.core.log.Lc;
|
|
import ru.touchin.roboswag.core.utils.ServiceBinder;
|
|
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
|
import rx.Completable;
|
|
import rx.CompletableSubscriber;
|
|
import rx.Observable;
|
|
import rx.Single;
|
|
import rx.SingleSubscriber;
|
|
import rx.Subscriber;
|
|
import rx.Subscription;
|
|
import rx.android.schedulers.AndroidSchedulers;
|
|
import rx.exceptions.OnErrorThrowable;
|
|
import rx.functions.Action0;
|
|
import rx.functions.Action1;
|
|
import rx.functions.Actions;
|
|
import rx.subjects.BehaviorSubject;
|
|
|
|
/**
|
|
* Created by Gavriil Sitnikov on 10/01/17.
|
|
* Base class of service to extends for Touch Instinct related projects.
|
|
* It contains {@link Logic} and could bind to it through {@link #untilDestroy(Observable)} methods.
|
|
*
|
|
* @param <TLogic> Type of application's {@link Logic}.
|
|
*/
|
|
public abstract class TouchinService<TLogic extends Logic> extends Service {
|
|
|
|
//it is needed to hold strong reference to logic
|
|
private TLogic reference;
|
|
@NonNull
|
|
private final Handler postHandler = new Handler();
|
|
@NonNull
|
|
private final BehaviorSubject<Boolean> isCreatedSubject = BehaviorSubject.create();
|
|
|
|
/**
|
|
* It should return specific class where all logic will be.
|
|
*
|
|
* @return Returns class of specific {@link Logic}.
|
|
*/
|
|
@NonNull
|
|
protected abstract Class<TLogic> getLogicClass();
|
|
|
|
@Override
|
|
public void onCreate() {
|
|
super.onCreate();
|
|
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
|
postHandler.post(() -> isCreatedSubject.onNext(true));
|
|
}
|
|
|
|
/**
|
|
* Returns (and creates if needed) application's logic.
|
|
*
|
|
* @return Object which represents application's logic.
|
|
*/
|
|
@NonNull
|
|
protected TLogic getLogic() {
|
|
synchronized (ViewControllerActivity.class) {
|
|
if (reference == null) {
|
|
reference = Logic.getInstance(this, getLogicClass());
|
|
}
|
|
}
|
|
return reference;
|
|
}
|
|
|
|
@SuppressWarnings("CPD-START")
|
|
//CPD: it is same as in other implementation based on BaseLifecycleBindable
|
|
/**
|
|
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to observable.
|
|
* Don't forget to process errors if observable can emit them.
|
|
*
|
|
* @param observable {@link Observable} to subscribe until onDestroy;
|
|
* @param <T> Type of emitted by observable items;
|
|
* @return {@link Subscription} which is wrapping source observable to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public <T> Subscription untilDestroy(@NonNull final Observable<T> observable) {
|
|
return untilDestroy(observable, Actions.empty(), getActionThrowableForAssertion(Lc.getCodePoint(this, 1)), Actions.empty());
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to observable and calls onNextAction on every emitted item.
|
|
* Don't forget to process errors if observable can emit them.
|
|
*
|
|
* @param observable {@link Observable} to subscribe until onDestroy;
|
|
* @param onNextAction Action which will raise on every {@link Subscriber#onNext(Object)} item;
|
|
* @param <T> Type of emitted by observable items;
|
|
* @return {@link Subscription} which is wrapping source observable to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public <T> Subscription untilDestroy(@NonNull final Observable<T> observable,
|
|
@NonNull final Action1<T> onNextAction) {
|
|
return untilDestroy(observable, onNextAction, getActionThrowableForAssertion(Lc.getCodePoint(this, 1)), Actions.empty());
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to observable and calls onNextAction and onErrorAction on observable events.
|
|
* Don't forget to process errors if observable can emit them.
|
|
*
|
|
* @param observable {@link Observable} to subscribe until onDestroy;
|
|
* @param onNextAction Action which will raise on every {@link Subscriber#onNext(Object)} item;
|
|
* @param onErrorAction Action which will raise on every {@link Subscriber#onError(Throwable)} throwable;
|
|
* @param <T> Type of emitted by observable items;
|
|
* @return {@link Subscription} which is wrapping source observable to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public <T> Subscription untilDestroy(@NonNull final Observable<T> observable,
|
|
@NonNull final Action1<T> onNextAction,
|
|
@NonNull final Action1<Throwable> onErrorAction) {
|
|
return untilDestroy(observable, onNextAction, onErrorAction, Actions.empty());
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to observable and calls onNextAction, onErrorAction and onCompletedAction on observable events.
|
|
* Don't forget to process errors if observable can emit them.
|
|
*
|
|
* @param observable {@link Observable} to subscribe until onDestroy;
|
|
* @param onNextAction Action which will raise on every {@link Subscriber#onNext(Object)} item;
|
|
* @param onErrorAction Action which will raise on every {@link Subscriber#onError(Throwable)} throwable;
|
|
* @param onCompletedAction Action which will raise at {@link Subscriber#onCompleted()} on completion of observable;
|
|
* @param <T> Type of emitted by observable items;
|
|
* @return {@link Subscription} which is wrapping source observable to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public <T> Subscription untilDestroy(@NonNull final Observable<T> observable,
|
|
@NonNull final Action1<T> onNextAction,
|
|
@NonNull final Action1<Throwable> onErrorAction,
|
|
@NonNull final Action0 onCompletedAction) {
|
|
return until(observable, isCreatedSubject.map(created -> !created), onNextAction, onErrorAction, onCompletedAction);
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that single won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to single.
|
|
* Don't forget to process errors if single can emit them.
|
|
*
|
|
* @param single {@link Single} to subscribe until onDestroy;
|
|
* @param <T> Type of emitted by single items;
|
|
* @return {@link Subscription} which is wrapping source single to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public <T> Subscription untilDestroy(@NonNull final Single<T> single) {
|
|
return untilDestroy(single, Actions.empty(), getActionThrowableForAssertion(Lc.getCodePoint(this, 1)));
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that single won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to single and calls onSuccessAction on emitted item.
|
|
* Don't forget to process errors if single can emit them.
|
|
*
|
|
* @param single {@link Single} to subscribe until onDestroy;
|
|
* @param onSuccessAction Action which will raise on {@link SingleSubscriber#onSuccess(Object)} item;
|
|
* @param <T> Type of emitted by single items;
|
|
* @return {@link Subscription} which is wrapping source single to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public <T> Subscription untilDestroy(@NonNull final Single<T> single, @NonNull final Action1<T> onSuccessAction) {
|
|
return untilDestroy(single, onSuccessAction, getActionThrowableForAssertion(Lc.getCodePoint(this, 1)));
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that single won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to single and calls onSuccessAction and onErrorAction on single events.
|
|
* Don't forget to process errors if single can emit them.
|
|
*
|
|
* @param single {@link Single} to subscribe until onDestroy;
|
|
* @param onSuccessAction Action which will raise on {@link SingleSubscriber#onSuccess(Object)} item;
|
|
* @param onErrorAction Action which will raise on every {@link SingleSubscriber#onError(Throwable)} throwable;
|
|
* @param <T> Type of emitted by single items;
|
|
* @return {@link Subscription} which is wrapping source single to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public <T> Subscription untilDestroy(@NonNull final Single<T> single,
|
|
@NonNull final Action1<T> onSuccessAction,
|
|
@NonNull final Action1<Throwable> onErrorAction) {
|
|
return until(single.toObservable(), isCreatedSubject.map(created -> !created), onSuccessAction, onErrorAction, Actions.empty());
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that completable won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to completable.
|
|
* Don't forget to process errors if completable can emit them.
|
|
*
|
|
* @param completable {@link Completable} to subscribe until onDestroy;
|
|
* @return {@link Subscription} which is wrapping source completable to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public Subscription untilDestroy(@NonNull final Completable completable) {
|
|
return untilDestroy(completable, Actions.empty(), getActionThrowableForAssertion(Lc.getCodePoint(this, 1)));
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that completable won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to completable and calls onCompletedAction on complete.
|
|
* Don't forget to process errors if completable can emit them.
|
|
*
|
|
* @param completable {@link Completable} to subscribe until onDestroy;
|
|
* @param onCompletedAction Action which will raise on every {@link CompletableSubscriber#onCompleted()} item;
|
|
* @return {@link Subscription} which is wrapping source completable to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public Subscription untilDestroy(@NonNull final Completable completable, @NonNull final Action0 onCompletedAction) {
|
|
return untilDestroy(completable, onCompletedAction, getActionThrowableForAssertion(Lc.getCodePoint(this, 1)));
|
|
}
|
|
|
|
/**
|
|
* Method should be used to guarantee that completable won't be subscribed after onDestroy.
|
|
* It is automatically subscribing to completable and calls onCompletedAction and onErrorAction on completable events.
|
|
* Don't forget to process errors if completable can emit them.
|
|
*
|
|
* @param completable {@link Single} to subscribe until onDestroy;
|
|
* @param onCompletedAction Action which will raise on {@link CompletableSubscriber#onCompleted()} item;
|
|
* @param onErrorAction Action which will raise on every {@link CompletableSubscriber#onError(Throwable)} throwable;
|
|
* @return {@link Subscription} which is wrapping source completable to unsubscribe from it onDestroy.
|
|
*/
|
|
@NonNull
|
|
public Subscription untilDestroy(@NonNull final Completable completable,
|
|
@NonNull final Action0 onCompletedAction,
|
|
@NonNull final Action1<Throwable> onErrorAction) {
|
|
return until(completable.toObservable(), isCreatedSubject.map(created -> !created), Actions.empty(), onErrorAction, onCompletedAction);
|
|
}
|
|
|
|
@NonNull
|
|
private <T> Subscription until(@NonNull final Observable<T> observable,
|
|
@NonNull final Observable<Boolean> conditionSubject,
|
|
@NonNull final Action1<T> onNextAction,
|
|
@NonNull final Action1<Throwable> onErrorAction,
|
|
@NonNull final Action0 onCompletedAction) {
|
|
final Observable<T> actualObservable;
|
|
if (onNextAction == Actions.empty() && onErrorAction == (Action1) Actions.empty() && onCompletedAction == Actions.empty()) {
|
|
actualObservable = observable;
|
|
} else {
|
|
actualObservable = observable.observeOn(AndroidSchedulers.mainThread())
|
|
.doOnCompleted(onCompletedAction)
|
|
.doOnNext(onNextAction)
|
|
.doOnError(onErrorAction);
|
|
}
|
|
|
|
return isCreatedSubject.first()
|
|
.switchMap(created -> created ? actualObservable : Observable.empty())
|
|
.takeUntil(conditionSubject.filter(condition -> condition))
|
|
.onErrorResumeNext(throwable -> {
|
|
final boolean isRxError = throwable instanceof OnErrorThrowable;
|
|
if ((!isRxError && throwable instanceof RuntimeException)
|
|
|| (isRxError && throwable.getCause() instanceof RuntimeException)) {
|
|
Lc.assertion(throwable);
|
|
}
|
|
return Observable.empty();
|
|
})
|
|
.subscribe();
|
|
}
|
|
|
|
@SuppressWarnings("CPD-END")
|
|
//CPD: it is same as in other implementation based on BaseLifecycleBindable
|
|
@NonNull
|
|
@Override
|
|
public IBinder onBind(@NonNull final Intent intent) {
|
|
return new ServiceBinder<>(this);
|
|
}
|
|
|
|
@Override
|
|
public void onLowMemory() {
|
|
super.onLowMemory();
|
|
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
|
postHandler.removeCallbacksAndMessages(null);
|
|
isCreatedSubject.onNext(false);
|
|
super.onDestroy();
|
|
}
|
|
|
|
@NonNull
|
|
private Action1<Throwable> getActionThrowableForAssertion(@NonNull final String codePoint) {
|
|
return throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on untilDestroy at " + codePoint, throwable));
|
|
}
|
|
|
|
}
|
|
|