diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/SimpleViewControllerFragment.java b/src/main/java/ru/touchin/roboswag/components/navigation/SimpleViewControllerFragment.java index 924c248..ea2b8b1 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/SimpleViewControllerFragment.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/SimpleViewControllerFragment.java @@ -25,12 +25,14 @@ import android.support.annotation.Nullable; import java.io.Serializable; +import ru.touchin.roboswag.components.utils.Logic; + /** * Created by Gavriil Sitnikov on 07/03/2016. * TODO: fill description */ -public class SimpleViewControllerFragment> - extends ViewControllerFragment { +public class SimpleViewControllerFragment> + extends ViewControllerFragment { private static final String VIEW_CONTROLLER_CLASS_EXTRA = "VIEW_CONTROLLER_CLASS_EXTRA"; @@ -49,13 +51,13 @@ public class SimpleViewControllerFragment>> viewControllerClass; + private Class>> viewControllerClass; @NonNull @Override - public Class>> getViewControllerClass() { + public Class>> getViewControllerClass() { return viewControllerClass; } @@ -63,8 +65,8 @@ public class SimpleViewControllerFragment>>) getArguments().getSerializable(VIEW_CONTROLLER_CLASS_EXTRA); + viewControllerClass = (Class>>) getArguments().getSerializable(VIEW_CONTROLLER_CLASS_EXTRA); } } diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/StatelessViewControllerFragment.java b/src/main/java/ru/touchin/roboswag/components/navigation/StatelessViewControllerFragment.java index f04cb42..d0751f0 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/StatelessViewControllerFragment.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/StatelessViewControllerFragment.java @@ -21,10 +21,12 @@ package ru.touchin.roboswag.components.navigation; import java.io.Serializable; +import ru.touchin.roboswag.components.utils.Logic; + /** * Created by Gavriil Sitnikov on 12/03/2016. * TODO: fill description */ -public class StatelessViewControllerFragment> - extends SimpleViewControllerFragment { +public class StatelessViewControllerFragment> + extends SimpleViewControllerFragment { } diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java b/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java index 903e3a7..bda173b 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java @@ -30,6 +30,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.ViewGroup; +import ru.touchin.roboswag.components.utils.Logic; import ru.touchin.roboswag.core.log.Lc; import rx.Observable; import rx.android.schedulers.AndroidSchedulers; @@ -39,14 +40,12 @@ import rx.subjects.BehaviorSubject; * Created by Gavriil Sitnikov on 21/10/2015. * Class to control view of specific fragment, activity and application by logic bridge. */ -public class ViewController, - TFragment extends ViewControllerFragment> { +public class ViewController, + TFragment extends ViewControllerFragment> { private static final String SUPPORT_FRAGMENT_VIEW_STATE_EXTRA = "android:view_state"; - @NonNull - private final TLogicBridge logicBridge; @NonNull private final TActivity activity; @NonNull @@ -56,9 +55,8 @@ public class ViewController isDestroyedSubject = BehaviorSubject.create(false); - public ViewController(@NonNull final CreationContext creationContext, + public ViewController(@NonNull final CreationContext creationContext, @Nullable final Bundle savedInstanceState) { - this.logicBridge = creationContext.logicBridge; this.activity = creationContext.activity; this.fragment = creationContext.fragment; this.container = creationContext.container; @@ -82,19 +80,19 @@ public class ViewController getRestoreSavedStateObservable(@NonNull final CreationContext creationContext, + protected Observable getRestoreSavedStateObservable(@NonNull final CreationContext creationContext, @Nullable final Bundle savedInstanceState) { return Observable.just(savedInstanceState); } /** - * Returns logic bridge to use and affect application logic. + * Returns application's logic. * - * @return Returns logic bridge object. + * @return Returns logic; */ @NonNull - public TLogicBridge getLogicBridge() { - return logicBridge; + public TLogic getLogic(){ + return getActivity().getLogic(); } /** @@ -177,12 +175,10 @@ public class ViewController, - TFragment extends ViewControllerFragment> { + public static class CreationContext, + TFragment extends ViewControllerFragment> { - @NonNull - private final TLogicBridge logicBridge; @NonNull private final TActivity activity; @NonNull @@ -190,21 +186,14 @@ public class ViewController extends BaseActivity { +public abstract class ViewControllerActivity extends BaseActivity { /** - * It should return specific Service class where from this fragment should get interface to logic. + * It should return specific class where from all logic will be. * - * @return Returns class of specific LogicService. + * @return Returns class of specific Logic. */ @NonNull - protected abstract Class> getLogicServiceClass(); + protected abstract Class getLogicClass(); /** - * Returns {@link Observable} which will connect to {@link LogicService} and get object of {@link TLogicBridge} type from it. + * Returns or creates application's logic. * - * @return {@link Observable} which will provide changes of object of type {@link TLogicBridge}; + * @return Object which represents application's logic. */ - @NonNull - public Observable observeLogicBridge() { - return RxAndroidUtils.observeService(this, getLogicServiceClass()) - .map(service -> service != null ? service.getLogicBridge() : null); + public TLogic getLogic() { + return Logic.getInstance(this, getLogicClass()); } } diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerFragment.java b/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerFragment.java index 3bb5e83..cdc465d 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerFragment.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerFragment.java @@ -35,11 +35,11 @@ import android.widget.FrameLayout; import java.io.Serializable; import java.lang.reflect.Constructor; +import ru.touchin.roboswag.components.utils.Logic; import ru.touchin.roboswag.core.log.Lc; import ru.touchin.roboswag.core.utils.ShouldNotHappenException; import rx.Observable; import rx.Subscription; -import rx.android.schedulers.AndroidSchedulers; import rx.exceptions.OnErrorThrowable; import rx.subjects.BehaviorSubject; @@ -47,7 +47,7 @@ import rx.subjects.BehaviorSubject; * Created by Gavriil Sitnikov on 21/10/2015. * Fragment instantiated in specific activity of {@link TActivity} type that is holding {@link ViewController} inside. */ -public abstract class ViewControllerFragment> +public abstract class ViewControllerFragment> extends ViewFragment { private static final String VIEW_CONTROLLER_STATE_EXTRA = "VIEW_CONTROLLER_STATE_EXTRA"; @@ -82,13 +82,13 @@ public abstract class ViewControllerFragment>> getViewControllerClass(); + public abstract Class>> getViewControllerClass(); @SuppressWarnings("unchecked") @Override @@ -110,21 +110,13 @@ public abstract class ViewControllerFragment createViewControllerObservable() { - return Observable - .combineLatest(activitySubject - .switchMap(activity -> activity != null ? activity.observeLogicBridge() : Observable.just(null)) - .distinctUntilChanged() - .observeOn(AndroidSchedulers.mainThread()), - activitySubject.distinctUntilChanged().observeOn(AndroidSchedulers.mainThread()), - viewSubject.distinctUntilChanged().observeOn(AndroidSchedulers.mainThread()), - this::getViewController); + return Observable.combineLatest(activitySubject.distinctUntilChanged(), viewSubject.distinctUntilChanged(), this::createViewController); } @Nullable - private ViewController getViewController(@Nullable final TLogicBridge logicBridge, - @Nullable final TActivity activity, - @Nullable final Pair viewInfo) { - if (logicBridge == null || activity == null || viewInfo == null) { + private ViewController createViewController(@Nullable final TActivity activity, + @Nullable final Pair viewInfo) { + if (activity == null || viewInfo == null) { return null; } @@ -132,9 +124,9 @@ public abstract class ViewControllerFragment constructor = getViewControllerClass().getConstructors()[0]; - final ViewController.CreationContext> creationContext - = new ViewController.CreationContext<>(logicBridge, activity, this, viewInfo.first); + final ViewController.CreationContext> creationContext + = new ViewController.CreationContext<>(activity, this, viewInfo.first); try { switch (constructor.getParameterTypes().length) { case 2: @@ -193,10 +185,9 @@ public abstract class ViewControllerFragment extends FragmentNavigation { +public class ViewControllerNavigation extends FragmentNavigation { @SuppressWarnings("CPD-START") - public ViewControllerNavigation(@NonNull final ViewControllerActivity context, + public ViewControllerNavigation(@NonNull final ViewControllerActivity context, @NonNull final FragmentManager fragmentManager, @IdRes final int containerViewId) { super(context, fragmentManager, containerViewId); } - public void push(@NonNull final Class>> fragmentClass, + public void push(@NonNull final Class>> fragmentClass, @NonNull final TState state) { addToStack(fragmentClass, null, ViewControllerFragment.createState(state), null, null); } - public void push(@NonNull final Class>> fragmentClass, + public void push(@NonNull final Class>> fragmentClass, @Nullable final TState state, @Nullable final Func1 transactionSetup) { addToStack(fragmentClass, null, ViewControllerFragment.createState(state), null, transactionSetup); } - public void pushForResult(@NonNull final Class>> fragmentClass, + public void pushForResult(@NonNull final Class>> fragmentClass, @NonNull final Fragment targetFragment, @NonNull final TState state) { addToStack(fragmentClass, targetFragment, ViewControllerFragment.createState(state), fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null); } - public void pushForResult(@NonNull final Class>> fragmentClass, + public void pushForResult(@NonNull final Class>> fragmentClass, @NonNull final Fragment targetFragment, @Nullable final TState state, @Nullable final Func1 transactionSetup) { @@ -54,73 +55,73 @@ public class ViewControllerNavigation extends FragmentNavigation { + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup); } - public void setAsTop(@NonNull final Class>> fragmentClass, + public void setAsTop(@NonNull final Class>> fragmentClass, @NonNull final TState state) { setAsTop(fragmentClass, ViewControllerFragment.createState(state), null); } - public void setAsTop(@NonNull final Class>> fragmentClass, + public void setAsTop(@NonNull final Class>> fragmentClass, @Nullable final TState state, @Nullable final Func1 transactionSetup) { setAsTop(fragmentClass, ViewControllerFragment.createState(state), transactionSetup); } - public void setInitial(@NonNull final Class>> fragmentClass, + public void setInitial(@NonNull final Class>> fragmentClass, @NonNull final TState state) { setInitial(fragmentClass, ViewControllerFragment.createState(state), null); } - public void setInitial(@NonNull final Class>> fragmentClass, + public void setInitial(@NonNull final Class>> fragmentClass, @Nullable final TState state, @Nullable final Func1 transactionSetup) { setInitial(fragmentClass, ViewControllerFragment.createState(state), transactionSetup); } - public void pushViewController(@NonNull final Class, - ? extends StatelessViewControllerFragment>>> viewControllerClass) { + public void pushViewController(@NonNull final Class, + ? extends StatelessViewControllerFragment>>> viewControllerClass) { addStatelessViewControllerToStack(viewControllerClass, null, null, null); } - public void pushViewController(@NonNull final Class, - ? extends SimpleViewControllerFragment>>> viewControllerClass, + public void pushViewController(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, @NonNull final TState state) { addViewControllerToStack(viewControllerClass, null, state, null, null); } - public void pushViewController(@NonNull final Class, - ? extends SimpleViewControllerFragment>>> viewControllerClass, + public void pushViewController(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, @Nullable final TState state, @Nullable final Func1 transactionSetup) { addViewControllerToStack(viewControllerClass, null, state, null, transactionSetup); } - public void pushViewControllerForResult(@NonNull final Class, - ? extends StatelessViewControllerFragment>>> viewControllerClass, + public void pushViewControllerForResult(@NonNull final Class, + ? extends StatelessViewControllerFragment>>> viewControllerClass, @NonNull final Fragment targetFragment) { addStatelessViewControllerToStack(viewControllerClass, targetFragment, viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null); } - public void pushViewControllerForResult(@NonNull final Class, - ? extends SimpleViewControllerFragment>>> viewControllerClass, + public void pushViewControllerForResult(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, @NonNull final Fragment targetFragment, @NonNull final TState state) { addViewControllerToStack(viewControllerClass, targetFragment, state, viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null); } - public void pushViewControllerForResult(@NonNull final Class, - ? extends SimpleViewControllerFragment>>> viewControllerClass, + public void pushViewControllerForResult(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, @NonNull final Fragment targetFragment, @Nullable final TState state, @Nullable final Func1 @@ -129,45 +130,45 @@ public class ViewControllerNavigation extends FragmentNavigation { + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup); } - public void setViewControllerAsTop(@NonNull final Class, - ? extends StatelessViewControllerFragment>>> viewControllerClass) { + public void setViewControllerAsTop(@NonNull final Class, + ? extends StatelessViewControllerFragment>>> viewControllerClass) { addStatelessViewControllerToStack(viewControllerClass, null, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, null); } - public void setViewControllerAsTop(@NonNull final Class, - ? extends SimpleViewControllerFragment>>> viewControllerClass, + public void setViewControllerAsTop(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, @NonNull final TState state) { addViewControllerToStack(viewControllerClass, null, state, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, null); } - public void setViewControllerAsTop(@NonNull final Class, - ? extends SimpleViewControllerFragment>>> viewControllerClass, + public void setViewControllerAsTop(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, @Nullable final TState state, @Nullable final Func1 transactionSetup) { addViewControllerToStack(viewControllerClass, null, state, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, transactionSetup); } - public void setInitialViewController(@NonNull final Class, - ? extends StatelessViewControllerFragment>>> viewControllerClass) { + public void setInitialViewController(@NonNull final Class, + ? extends StatelessViewControllerFragment>>> viewControllerClass) { beforeSetInitialActions(); setViewControllerAsTop(viewControllerClass); } - public void setInitialViewController(@NonNull final Class, - ? extends SimpleViewControllerFragment>>> viewControllerClass, + public void setInitialViewController(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, @NonNull final TState state) { setInitialViewController(viewControllerClass, state, null); } - public void setInitialViewController(@NonNull final Class, - ? extends SimpleViewControllerFragment>>> viewControllerClass, + public void setInitialViewController(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, @Nullable final TState state, @Nullable final Func1 transactionSetup) { @@ -176,7 +177,7 @@ public class ViewControllerNavigation extends FragmentNavigation { } protected void addViewControllerToStack( - @NonNull final Class, ?>> viewControllerClass, + @NonNull final Class, ?>> viewControllerClass, @Nullable final Fragment targetFragment, @Nullable final TState state, @Nullable final String backStackTag, @@ -187,7 +188,7 @@ public class ViewControllerNavigation extends FragmentNavigation { @SuppressWarnings("CPD-END") protected void addStatelessViewControllerToStack( - @NonNull final Class, ?>> viewControllerClass, + @NonNull final Class, ?>> viewControllerClass, @Nullable final Fragment targetFragment, @Nullable final String backStackTag, @Nullable final Func1 transactionSetup) { diff --git a/src/main/java/ru/touchin/roboswag/components/services/LogicService.java b/src/main/java/ru/touchin/roboswag/components/services/LogicService.java deleted file mode 100644 index 9550777..0000000 --- a/src/main/java/ru/touchin/roboswag/components/services/LogicService.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov) - * - * 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.roboswag.components.services; - -import android.app.IntentService; -import android.content.Intent; -import android.os.IBinder; - -import ru.touchin.roboswag.core.utils.android.ServiceBinder; - -/** - * Created by Gavriil Sitnikov on 10/01/2016. - * Service which holds interface to all application's logic objects and methods. - * Any part of application should interact with some part of logic via this interface. - * If it is Service, Activity, Fragment or view then it should bind itself to that service first then get service and logic bridge from IBinder. - * If it is BroadcastReceiver then it should start service which can bind to that service or just send some intent to that service. - * [phase 1] - */ -public abstract class LogicService extends IntentService { - - private TLogicBridge logicBridge; - - protected LogicService() { - super("LogicService"); - } - - @Override - public void onCreate() { - super.onCreate(); - this.logicBridge = createLogicBridge(); - } - - @Override - protected void onHandleIntent(final Intent intent) { - // do nothing - } - - /** - * Creates object which will provide all logic methods and objects of application. - * Any other activity, fragment or service should bind to that service to get logic bridge and start interact with application's logic. - * Do not initialize massive objects during creation as this operation is calling on UI thread. - * - * @return Returns instantiated logic bridge. - */ - protected abstract TLogicBridge createLogicBridge(); - - /** - * Returns interface to application's logic. - * - * @return Returns logic bridge object. - */ - public TLogicBridge getLogicBridge() { - return logicBridge; - } - - @Override - public IBinder onBind(final Intent intent) { - return new ServiceBinder<>(this); - } - -} diff --git a/src/main/java/ru/touchin/roboswag/components/utils/Logic.java b/src/main/java/ru/touchin/roboswag/components/utils/Logic.java new file mode 100644 index 0000000..48dcac7 --- /dev/null +++ b/src/main/java/ru/touchin/roboswag/components/utils/Logic.java @@ -0,0 +1,51 @@ +package ru.touchin.roboswag.components.utils; + +import android.content.Context; +import android.support.annotation.NonNull; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Map; + +/** + * Created by Gavriil Sitnikov on 24/03/16. + * TODO: description + */ +public abstract class Logic { + + private final static Map, WeakReference> LOGIC_INSTANCES = new HashMap<>(); + + @SuppressWarnings("unchecked") + @NonNull + public static T getInstance(@NonNull final Context context, @NonNull final Class logicClass) { + T result; + synchronized (LOGIC_INSTANCES) { + final WeakReference reference = LOGIC_INSTANCES.get(logicClass); + result = reference != null ? (T) reference.get() : null; + if (result == null) { + result = constructLogic(context.getApplicationContext(), logicClass); + LOGIC_INSTANCES.put(logicClass, new WeakReference<>(result)); + } + } + return result; + } + + @SuppressWarnings("unchecked") + private static T constructLogic(@NonNull final Context context, @NonNull final Class logicClass) { + if (logicClass.getConstructors().length != 1 || logicClass.getConstructors()[0].getParameterTypes().length != 1) { + throw new IllegalArgumentException("There should be only one public constructor(Context) for class " + logicClass); + } + final Constructor constructor = logicClass.getConstructors()[0]; + try { + return (T) constructor.newInstance(context); + } catch (final Exception exception) { + throw new IllegalStateException(exception); + } + } + + public Logic(@NonNull final Context context) { + //do nothing + } + +}