diff --git a/app/src/main/java/j4ckall/rxflux/lib/flux/Action.java b/app/src/main/java/j4ckall/rxflux/lib/flux/Action.java new file mode 100644 index 0000000..8d9876e --- /dev/null +++ b/app/src/main/java/j4ckall/rxflux/lib/flux/Action.java @@ -0,0 +1,26 @@ +package j4ckall.rxflux.lib.flux; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +/** + * ユーザアクション毎の内容を表すクラス + * Keyはアクションを識別するためのもの + * ユーザアクションの発生毎にImmutableなインスタンスが生成される + * + * @author matsumoto_k + */ +public class Action { + public final Key key; + public final T value; + final boolean notifyStoreChanged; + + public interface Key { + } + + Action(@NonNull Key key, @Nullable T t, @NonNull boolean notifyStoreChanged) { + this.key = key; + this.value = t; + this.notifyStoreChanged = notifyStoreChanged; + } +} diff --git a/app/src/main/java/j4ckall/rxflux/lib/flux/ActionCreater.java b/app/src/main/java/j4ckall/rxflux/lib/flux/ActionCreater.java new file mode 100644 index 0000000..a24e978 --- /dev/null +++ b/app/src/main/java/j4ckall/rxflux/lib/flux/ActionCreater.java @@ -0,0 +1,41 @@ +package j4ckall.rxflux.lib.flux; + + +import android.support.annotation.NonNull; + +/** + * Actionを作成するHelper + * DispatcherにActionを流す + * + * @author matsumoto_k + */ +public abstract class ActionCreater { + + private final Dispatcher dispatcher; + + public ActionCreater(Dispatcher dispatcher) { + this.dispatcher = dispatcher; + } + + /** + * DispatcherにActionを流す(通知有) + * + * @param key Action識別子 + * @param value + * @param + */ + protected final void dispatch(@NonNull Action.Key key, @NonNull T value) { + dispatcher.dispatch(new Action(key, value, true)); + } + + /** + * DispatcherにActionを流す(通知無) + * + * @param key + * @param value + * @param + */ + protected final void dispatchSkipNotify(@NonNull Action.Key key, @NonNull T value) { + dispatcher.dispatch(new Action(key, value, false)); + } +} diff --git a/app/src/main/java/j4ckall/rxflux/lib/flux/Dispatcher.java b/app/src/main/java/j4ckall/rxflux/lib/flux/Dispatcher.java new file mode 100644 index 0000000..a578b60 --- /dev/null +++ b/app/src/main/java/j4ckall/rxflux/lib/flux/Dispatcher.java @@ -0,0 +1,42 @@ +package j4ckall.rxflux.lib.flux; + +import java.util.Objects; + +import io.reactivex.Observable; +import io.reactivex.functions.Consumer; +import io.reactivex.subjects.PublishSubject; +import io.reactivex.subjects.Subject; + +/** + * ActionをトリガーにしてdispatcherSubjectを購読しているStoreにデータを流す + * + * @author matsumoto_k + */ +public class Dispatcher { + + private final Subject dispatcherSubject = PublishSubject.create().toSerialized(); + + public Dispatcher() { + } + + /** + * dispatcherSubjectを購読する + * + * @param key + * @param subscriber + * @return + */ + final Observable on(Action.Key key, Consumer subscriber) { + return dispatcherSubject.filter(fluxAction -> Objects.equals(fluxAction.key, key)) + .doOnNext(subscriber); + } + + /** + * dispatcherSubjectを購読しているStoreにデータを流す + * + * @param fluxAction + */ + final void dispatch(Action fluxAction) { + dispatcherSubject.onNext(fluxAction); + } +} diff --git a/app/src/main/java/j4ckall/rxflux/lib/flux/Store.java b/app/src/main/java/j4ckall/rxflux/lib/flux/Store.java new file mode 100644 index 0000000..70f0dd0 --- /dev/null +++ b/app/src/main/java/j4ckall/rxflux/lib/flux/Store.java @@ -0,0 +1,90 @@ +package j4ckall.rxflux.lib.flux; + +import io.reactivex.Scheduler; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.functions.Consumer; +import io.reactivex.schedulers.Schedulers; +import io.reactivex.subjects.PublishSubject; +import io.reactivex.subjects.Subject; + + +/** + * アプリケーションの状態を管理する + * ストリームから流れてくるActionを受け取り、Actionの内容によって + * Storeの状態を更新する + * Store毎のストリームを保持し、ストリームを購読しているActivity/Fragment等へ + * 情報変更を通知する + * TODO:MVP,MVVMなどに対応させる + * + * @author matsumoto_k + */ +public abstract class Store implements Action.Key { + + private final Subject storeSubject = PublishSubject.create().toSerialized(); + private final Dispatcher dispatcher; + private final CompositeDisposable subscriptions = new CompositeDisposable(); + + public Store(Dispatcher dispatcher) { + this.dispatcher = dispatcher; + } + + private void observe(Scheduler scheduler, Consumer subscriber) { + subscriptions.add(storeSubject + .subscribeOn(Schedulers.computation()) + .observeOn(scheduler) + .subscribe(subscriber) + ); + } + + /** + * UI層でのstoreSubject購読 + * + * @param subscriber + */ + public void observeOnMainThread(Consumer subscriber) { + observe(AndroidSchedulers.mainThread(), subscriber); + } + + /** + * 非UI層でのstoreSubject購読 + * + * @param subscriber + */ + public void observeOnBackgroundThread(Consumer subscriber) { + observe(Schedulers.computation(), subscriber); + } + + /** + * ストアの状態が変わったことを通知する + * + * @param fluxAction + */ + private void notifyStoreChanged(Action fluxAction) { + storeSubject.onNext(fluxAction); + } + + /** + * StoreでDispatcherのsubject(アクションイベント)の購読 + * + * @param key + * @param subscriber + */ + protected void on(Action.Key key, Consumer subscriber) { + dispatcher.on(key, subscriber) + .subscribeOn(Schedulers.computation()) + .subscribe(fluxAction -> { + if (fluxAction.notifyStoreChanged) { + notifyStoreChanged(fluxAction); + } + }); + } + + public void clear() { + subscriptions.clear(); + } + + public void unSubscribe() { + subscriptions.dispose(); + } +}