简介
RxFlux 是一个使用 RxJava1 实现 Flux模式 的轻量级框架,RxFlux 仅仅提供 Flux 模式的一种实现,它需要手动集成,并且需要开发者遵守 Flux 步骤才可以正常工作。
优势: 架构清晰、步骤简单、逻辑抽象、容易测试、模块化、响应式、添加 Hooks 容易。
不足: 线性逻辑、不同的模式,使用前需要学习。
Wiki-1:Getting started
RxFlux 是一个框架,意味着需要做一些准备工作,而不仅仅是作为一个 library。使用 RxFlux 框架最好了解 RxJava 和 Flux。如果你需要更多的知识来理解 Android 中的 Flux 模式,可以查看 @lgvalle 创建的 例子和说明 。
记住 Flux 的框架能更好的理解 RxFlux。
Flux architecture
第一步添加 RxFlux 到 build.gradle 文件中:
dependencies { compile 'com.hardsoftstudio:rxflux:latest' }
public void onCreate() { super.onCreate(); rxFlux = RxFlux.init(); }
Wiki-2:Setup Action
创建接口 Actions 包含你的 actions:
public interface Actions { String GET_PUBLIC_REPOS = "get_public_repos"; void getPublicRepositories(); String GET_USER = "get_user"; void getUserDetails(String userId); }
创建一个 RxActionCreator 类将创建 RxAction 根据前面的接口 Actions:
public class GitHubActionCreator extends RxActionCreator implements Actions { public GitHubActionCreator(Dispatcher dispatcher, SubscriptionManager manager) { super(dispatcher, manager); } //实现定义的actions }
大部分的 actions 是请求一个 API,DB 或你想执行的操作。因此创建 RxAction 时,您必须返回这些请求的结果。推荐创建一个接口 Keys,将帮助我们整理数据。
public interface Keys { String PUBLIC_REPOS = "repos"; String USER = "user"; String ID = "id"; }
创建第一个 action:
@Override public void getUserDetails(String userId) { final RxAction action = newRxAction(GET_USER, Keys.ID, userId); ... }
方法 newRxAction() 帮助你创建一个新的 RxAction。传入参数 action type 和 key-value。
现在我们有一个 RxAction,我们可以请求 API 或处理一些逻辑来获取所需的 action 的结果。
@Override public void getUserDetails(String userId) { final RxAction action = newRxAction(GET_USER, Keys.ID, userId); addRxAction(action, NetworkManager.getApi() .getUser(userId) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(user -> { action.getData().put(USER, user); postRxAction(action); }, throwable -> postError(action, throwable))); }
这里我们使用 RxJava,我们创建一个新的 Observable 并执行 subscribe。产生的 Subscription 被添加到 SubscriptionManager。
当这个 Subscription 返回一个有效的数据时,我们用 key-value 加入到 RxAction。然后我们使用预定义的方法 postRxAction() 发送 action 到 Dispatcher。
在出错的情况下,我们将使用预定义的方法 postError() 发送一个 error 到 Dispatcher。
为避免重复的请求,当你添加一个 Subscription 到 SubscriptionManager,这个 Subscription 将保存直到它被 unsubscribed。使用 hasRxAction(RxAction) 方法来检查是否有一个正在进行 Subscription。
@Override public void getUserDetails(String userId) { final RxAction action = newRxAction(GET_USER, Keys.ID, userId); if (hasRxAction(action)) return; // Return or cancel previous ... }
Wiki-3:Setup Store
第一步定义 store,创建接口。
public interface RepositoriesStoreInterface { ArrayList getRepositories(); }
创建一个 store 继承 RxStore。
public class RepositoriesStore extends RxStore implements RepositoriesStoreInterface { ... }
RxStore 是一个抽象类,同 Dispatcher 一起处理 subscription 来接收 actions。为接收这些 actions,我们需要实现 onRxAction() 。
public class RepositoriesStore extends RxStore implements RepositoriesStoreInterface { public RepositoriesStore(Dispatcher Dispatcher) { super(Dispatcher); } @Override public void onRxAction(RxAction action) { } }
构造函数需要 Dispatcher 作为参数,以便订阅它。 onRxAction() 方法将得到Dispatcher 发布的所有 actions。使用 switch 语句来过滤这些 actions。
@Override public void onRxAction(RxAction action) { switch (action.getType()) { case Actions.GET_PUBLIC_REPOS: this.gitHubRepos = action.get(Keys.PUBLIC_REPOS); break; default: // IMPORTANT 不需要处理的action,被忽略 return; } postChange(new RxStoreChange(ID, action)); }
因为 store 将接收所有类型的 actions,而我们只处理那些我们关心的。为了做到这一点,我们检索 actions 中数据并处理,然后发布一个 RxStoreChange,通知 views。使用方法 postChange() 发布 RxStoreChange。这种方法发布的RxStoreChange 包含将一个给定的 store id (主要用于标识那个 store 发出的)和 RxAction。
最后一步是实现公共接口,提供的我们想要的数据。
@Override public ArrayList getRepositories() { return gitHubRepos == null ? new ArrayList() : gitHubRepos; }
views 可以在接收到一个 RxStoreChange 时或者任何需要的时候,调用该方法,得到 store 中的数据。
Wiki-4:Setup View
views 负责触发 actions,注册 stores 并使用 stores 的数据。
第一步是项目中的每个 activity 必须实现 RxViewDispatch。
getRxStoreListToRegister() 告诉 RxFlux 哪个 store 需要注册。
@Override public List getRxStoreListToRegister() { repositoriesStore = RepositoriesStore.get(SampleApp.get(this).getRxFlux().getDispatcher()); usersStore = UsersStore.get(SampleApp.get(this).getRxFlux().getDispatcher()); return Arrays.asList(repositoriesStore, usersStore); }
我们如何建立我们的商店。在这个例子中,我们得到的需要注册的 store 的实例。RxFlux 在 activity 创建成功之后会调用该方法,若 activity 是 RxViewDispatch 的子类,获取需要注册的 RxStoreList 并调用 RxStore 中的方法 register() ,注册 store 到 Dispatcher 中。
Note: 为了安全,在多次调用注册时,我们只注册一次。
onRxStoreChanged() 在每次 store 发送一个 RxStoreChange 的时候将被调用。
@Override public void onRxStoreChanged(RxStoreChange change) { switch (change.getStoreId()) { case RepositoriesStore.ID: switch (change.getRxAction().getType()) { case Actions.GET_PUBLIC_REPOS: adapter.setRepos(repositoriesStore.getRepositories()); break; } break; } }
RxStoreChange 有一个 store 的标识和一个 RxAction。通过这两个,views 可以执行期望的逻辑。
onRxError() 在 RxError 被 post 到 Dispatcher 时调用。
@Override public void onRxError(RxError error) { setLoadingFrame(false); Throwable throwable = error.getThrowable(); if (throwable != null) { Snackbar.make(coordinatorLayout, "An error ocurred", Snackbar.LENGTH_INDEFINITE) .setAction("Retry", v -> SampleApp.get(this).getGitHubActionCreator().retry(error.getAction())) .show(); } else { Toast.makeText(this, "Unknown error", Toast.LENGTH_LONG).show(); } }
这种方法允许我们作出反应,当我们得到一个错误时。注意 RxError 包含期望的 RxAction。因此,我们可以使用它来重试或显示适当的信息。
RxViewDispatcher 的最后两个方法是用来注册其他非 activity 的 view(fragments,customViews等)。
@Override public void onRxViewRegistered() { // If there is any fragment that needs to register store changes we can do it here } @Override public void onRxViewUnRegistered() { // If there is any fragment that has registered for store changes we can unregister now }
高级选项
RxFlux 将管理应用程序生命周期,在正确的时候注册和注销 views,避免内存泄漏。如果应用程序被destroyed,还将负责清理任何订阅。
有关更多信息,请查看 RxFlux.class (主类,负责连接每个部分,基于 Android 的生命周期)。
Flow
- RxFlux 会在 activity 创建时,注册我们所需要的 store,调用
getRxStoreListToRegister() 。 - 在 activity resume 时,RxFlux 将注册这个 activity 到 Dispatcher 中。
- 在 activity pause 时,RxFlux 从 Dispatcher 中解除这个 activity 的注册。
- 当最后一个 activity 被 destroy 时,RxFlux 将调用关闭。
为什么在 onResume() 注册和在 onPause() 注销?
根据 activity 的生命周期来处理注册和解除注册,这是正确的方法,可以避免当 view 不在前台的时候,获取 RxStoreChange 并响应触发 UI 变化。
一个良好的实践是在 onResume() 期间,检查 store 的状态并更新 UI。
公共方法
public static RxFlux init(Application application) { if (instance != null) throw new IllegalStateException("Init was already called"); return instance = new RxFlux(application); }
初始化 RxFlux 框架,必须在 Application 创建时调用此方法,并只有一次。
public static void shutdown() { if (instance == null) return; instance.subscriptionManager.clear(); instance.Dispatcher.unregisterAll(); }
调用这个方法停止应用程序,清理所有的订阅和注册。
public RxBus getRxBus() { return rxBus; }
RxBus 的实例,如果您想在您的应用程序中重用作为默认的 bus system。
public Dispatcher getDispatcher() { return Dispatcher; }
Dispatcher 的实例,负责处理订阅,传送 bus event 到正确的位置。在创建 RxActionCreator 时,使用这个实例。
public SubscriptionManager getSubscriptionManager() { return subscriptionManager; }
SubscriptionManager 的实例,以便你想要重用的别的东西。在创建 RxActionCreator 时,使用这个实例。