From b27264469a0e46ed14dcd91f6a02c19d054299d2 Mon Sep 17 00:00:00 2001 From: Gavriil Sitnikov Date: Thu, 12 Jan 2017 16:56:42 +0300 Subject: [PATCH] touchin service added --- .../ru/touchin/templates/TouchinService.java | 193 ++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 src/main/java/ru/touchin/templates/TouchinService.java diff --git a/src/main/java/ru/touchin/templates/TouchinService.java b/src/main/java/ru/touchin/templates/TouchinService.java new file mode 100644 index 0000000..c7eb210 --- /dev/null +++ b/src/main/java/ru/touchin/templates/TouchinService.java @@ -0,0 +1,193 @@ +/* + * 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.core.log.Lc; +import ru.touchin.roboswag.core.utils.ServiceBinder; +import ru.touchin.roboswag.core.utils.ShouldNotHappenException; +import rx.Observable; +import rx.Subscriber; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +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 Type of application's {@link Logic}. + */ +public abstract class TouchinService 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 isCreatedSubject = BehaviorSubject.create(); + + /** + * It should return specific class where all logic will be. + * + * @return Returns class of specific {@link Logic}. + */ + @NonNull + protected abstract Class getLogicClass(); + + @Override + public void onCreate() { + super.onCreate(); + 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 Type of emitted by observable items; + * @return {@link Observable} which is wrapping source observable to unsubscribe from it onDestroy. + */ + @NonNull + public Subscription untilDestroy(@NonNull final Observable observable) { + final String codePoint = Lc.getCodePoint(this, 1); + return untilDestroy(observable, Actions.empty(), + throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on untilDestroy at " + codePoint, throwable)), + 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 Type of emitted by observable items; + * @return {@link Observable} which is wrapping source observable to unsubscribe from it onDestroy. + */ + @NonNull + public Subscription untilDestroy(@NonNull final Observable observable, + @NonNull final Action1 onNextAction) { + final String codePoint = Lc.getCodePoint(this, 1); + return untilDestroy(observable, onNextAction, + throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on untilDestroy at " + codePoint, throwable)), + 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 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 Type of emitted by observable items; + * @return {@link Observable} which is wrapping source observable to unsubscribe from it onDestroy. + */ + @NonNull + public Subscription untilDestroy(@NonNull final Observable observable, + @NonNull final Action1 onNextAction, + @NonNull final Action1 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, 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 Type of emitted by observable items; + * @return {@link Observable} which is wrapping source observable to unsubscribe from it onDestroy. + */ + @NonNull + public Subscription untilDestroy(@NonNull final Observable observable, + @NonNull final Action1 onNextAction, + @NonNull final Action1 onErrorAction, + @NonNull final Action0 onCompletedAction) { + return until(observable, isCreatedSubject.map(created -> !created), onNextAction, onErrorAction, onCompletedAction); + } + + @NonNull + private Subscription until(@NonNull final Observable observable, + @NonNull final Observable conditionSubject, + @NonNull final Action1 onNextAction, + @NonNull final Action1 onErrorAction, + @NonNull final Action0 onCompletedAction) { + return isCreatedSubject.first() + .switchMap(created -> created + ? observable.observeOn(AndroidSchedulers.mainThread()).doOnCompleted(onCompletedAction) + : Observable.empty()) + .takeUntil(conditionSubject.filter(condition -> condition)) + .subscribe(onNextAction, onErrorAction); + } + + @SuppressWarnings("CPD-END") + //CPD: it is same as in other implementation based on BaseLifecycleBindable + @NonNull + @Override + public IBinder onBind(final Intent intent) { + return new ServiceBinder<>(this); + } + + @Override + public void onDestroy() { + postHandler.removeCallbacksAndMessages(null); + isCreatedSubject.onNext(false); + super.onDestroy(); + } + +} +