android redux 架构,Redux 在 Android 中的应用

背景

参考前端学习系列2:从移动端的角度学习与分析Redux一文,在React中Redux框架被用来将展示与数据分离以及管理状态的变化,扩展性非常好,而且便于测试,那我们不禁想到,能不能把这样一套框架移植到Android原生开发中来。

Redux核心框架

android redux 架构,Redux 在 Android 中的应用_第1张图片

上图展示了Redux的数据流向:

当用户操作View时可能引发数据的变化,这时候会经由ActionCreator产生特定的Action传递给Store;

Store在接收到Action后,将其分发给Reducer进行处理,而Reducer内部会根据Action更新对应的数据,产生新的State返回给Store;

Store最终将更新的状态State通知给View,改变UI刷新页面

TODO应用

基础功能实现过程

我们先看下基于Redux框架如何完成添加TODO item以及修改item状态这些基本功能:

定义状态State

在TODO应用中我们首先需要保存一个TODO item的信息列表,因此state应该对应的是List这样一种数据类型

定义交互的Actions

·每一个Action应该包含两部分内容,一部分是Action的类型标识,另一个部分传递的是附加的数据。

public class Action { public final String type; public final Object value; public Action(String type, Object value) {...}

}

具体到本应用,我们需要创建添加和修改item这两种操作对应的Action,为了保证代码的复用和整洁,通常Action的创建要依赖ActionCreator。

public class TodoActions{ public static final String ADD_ITEM = "ADD_ITEM"; public static final String CHANGE_STATE = "CHANGE_STATE"; public static Action addItem(TodoItem item){ return new Action(ADD_ITEM, item);

} public static Action changeState(long id, boolean isChecked){ return new Action(CHANGE_STATE, Pair.create(id, isChecked));

}

}

创建Reducer

在定义好Actions后,我们需要知道如何去处理它们,也就是实现Reducer接口

public interface Reducer{ State reduce(State state, Action action);

}

reduce方法接收两个参数,一个是当前状态,另一个是需要处理的Action。在处理完成后它返回的是更新的状态。

下面的TodoReducer展示了本应用中具体的action处理过程:

public class TodoReducer implements Reducer>{ List addItem(List items, TodoItem item){ return TreePVector.from(items)

.plus(item);

} List changeState(List items, long id, boolean isChecked){ for (int i = 0; i < items.size(); i++) {

TodoItem todoItem = items.get(i); if (todoItem.id == id) {

TodoItem changed = new TodoItem(id, todoItem.text, isChecked); return TreePVector.from(items)

.with(i, changed);

}

} return items;

} @Override public List reduce(List items, Action action){ switch (action.type) { case TodoActions.ADD_ITEM:

TodoItem todoItem = (TodoItem) action.value; return addItem(items, todoItem); case TodoActions.CHANGE_STATE:

Pair pair = (Pair) action.value; long id = pair.first; boolean isChecked = pair.second; return changeState(items, id, isChecked); default: return items;

}

}

}

创建Store

Store是State的容器,一个Store通常得实现以下几个方法

public class Store{ public State getState(); public void dispatch(Object action); public Cancelable subscribe(StateChangeListener listener); public interface StateChangeListener{ void onStateChanged(S state);

}

}

getState(): 获取当前状态

dispatch(): 将action分发给对应的reducer

subcribe(): 注册状态的监听器,如果产生新状态则将其回调出去

这里给出Store的一种实现:

public class Store implements Dispatcher, Cursor{ public static final String INIT_ACTION = "@@reductor/INIT"; private final Reducer reducer; private final Dispatcher dispatcher; private final List> listeners = new CopyOnWriteArrayList<>(); private volatile State state; private Store(Reducer reducer, State initialState, Middleware[] middlewares){ this.reducer = reducer; this.state = initialState;

Dispatcher dispatcher = this::dispatchAction; for (int i = middlewares.length - 1; i >= 0; i--) {

Middleware middleware = middlewares[i];

dispatcher = middleware.create(Store.this, dispatcher);

} this.dispatcher = dispatcher;

dispatchAction(Action.create(INIT_ACTION));

} private void dispatchAction(final Object actionObject){ if (actionObject instanceof Action) { final Action action = (Action) actionObject; synchronized (this) {

state = reducer.reduce(state, action);

} for (StateChangeListener listener : listeners) {

listener.onStateChanged(state);

}

} else { throw new IllegalArgumentException(String.format("action %s of %s is not instance of %s, use custom Middleware to dispatch another types of actions", actionObject, actionObject.getClass(), Action.class));

}

} public static Store create(Reducer reducer, S initialState, Middleware... middlewares){ return new Store<>(reducer, initialState, middlewares);

} public void dispatch(final Object action){

dispatcher.dispatch(action);

} public State getState(){ return state;

} public Cancelable subscribe(final StateChangeListener listener){

listeners.add(listener); return () -> listeners.remove(listener);

}

}

编写界面Activity

有了以上这些组件以后,我们可以很轻松地完成UI界面的编写

public class MainActivity extends AppCompatActivity{

Store> todoStore;

TodoAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); //boilerplate code ... //Creating Store object with empty list as initial state todoStore = Store.create(new TodoReducer(), Collections.emptyList());

todoStore.subscribe(state -> adapter.notifyDataSetChanged());

} void addNote(String text){

TodoItem todoItem = new TodoItem(generateId(), text, false);

todoStore.dispatch(TodoActions.addItem(todoItem));

} void changeState(long id, boolean isChecked){

todoStore.dispatch(TodoActions.changeState(id, isChecked));

}

}

高级功能

Reducer组合

随着业务的累加,将所有action的处理都放到一个Reducer中显然是不合理的,我们可以在Store内部维护多个Reducer,每个Reducer只处理特定的数据。

例如:当要增加根据当前状态筛选所有TODO item的功能时,我们可以先定义新的组合状态

public enum TodoFilter {

ALL,

CHECKED,

UNCHECKED

} public class AppState{ public final List todoItems; public final TodoFilter filter; public AppState(List todoItems, TodoFilter filter){ this.todoItems = todoItems; this.filter = filter;

}

}

而在处理action时再将其分发对应的子reducer处理

public class AppStateReducer implements Reducer{ private Reducer> itemsReducer = TodoReducer.create(); private Reducer filterReducer = FilterReducer.create(); @Override public AppState reduce(AppState state, Action action){

List items = itemsReducer.reduce(state.todoItems, action);

TodoFilter filter = filterReducer.reduce(state.filter, action); return new AppState(items, filter);

}

}

操作回滚

Redux的架构让State的管理保存变得极为方便,也让状态回滚成为可能,在TODO应用中可以这样实现:

public class UndoableReducer implements Reducer{ private final Reducer sourceReducer; public static Action pop(){ return Action.create("POP");

} private LinkedList stack = new LinkedList<>(); public UndoableReducer(Reducer sourceReducer){ this.sourceReducer = sourceReducer;

} @Override public State reduce(State state, Action action){ if (action.type.equals("POP")) { return stack.isEmpty()

? state

: stack.pop();

} else if (!action.type.equals(Store.INIT_ACTION)){

stack.push(state);

} return sourceReducer.reduce(state, action);

}

}

中间件

中间件提供的是位于 action 被发起之后,到达 reducer 之前的扩展点,你可以利用它来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。

以打log为例

public class LogMiddleware implements Middleware{ @Override public Dispatcher create(Store store, Dispatcher nextDispatcher){ return action -> {

Log.d("LogMiddleware", "dispatch action:" + action + ",current state:" + store.getState());

nextDispatcher.dispatch(action);

Log.d("LogMiddleware", "next state:" + store.getState());

};

}

}

Redux的优缺点

优势

View和Model解耦,View变得非常薄,只包含渲染逻辑和触发action两个职责

观察理解数据状态的变化,只用看它注册的所有action就行,排查问题以及做单测非常方便,最牛叉的是可以做到历史回滚

中间件的自由组合

特别适合组件之间有数据交互的情况

按照Redux这种模式写出来的代码风格容易统一

缺点

State通常是一个统一的状态树,如果页面被分拆成了许多相对独立的Fragment或者组件,用统一的状态树去管理容易将问题复杂化

和前端有一堆轮子相比,Android原生开发使用Redux编写过程异常繁琐,需要创建很多类,并且在处理复杂业务逻辑时不如MVP等模式来的直接易懂

你可能感兴趣的:(android,redux,架构)