AndroidFlux

来源:互联网 发布:威纶触摸屏数据导出 编辑:程序博客网 时间:2024/06/05 16:52

无意中看到AndroidFlux,就了解了一下,整理出来记录一下。


什么是AndroidFlux(官方介绍)

AndroidFlux是Facebook的Flux 架构的Android实现。Flux是Facebook在14年提出的一种Web前端架构,主要用来处理复杂的UI逻辑的一致性问题(当时是为了解决Web页面的消息通知问题)。经过实践之后发现,这种架构可以很好的应用于Android平台,相对于其他的MVC/MVP/MVVM等模式,拥有良好的文档和更具体的设计,比较适合于快速开发实现。

Flux模式最大的特点是单向的数据流,它的UI状态更新模式继承了MVC模式的设计思想。Flux并不是具体的框架,而是一套处理UI问题的模式。

这里写图片描述

Flux应用程序包含三个主要部分:Dispatcher、Store和View。需要注意的是这和MVC的Model-View-Controller并不是对应关系,这里的View是Controller-View,负责处理UI逻辑和一些简单的事件分发,而在Android平台中,完美的对应的到Activity(或Fragment)和相应的布局文件(layout.xml)。Store部分也不是Model(业务Model),而是维护UI状态的PresentationModel,用来维护一组逻辑相关的UI状态。Dispatcher不会被直接使用,而是通过通过一个帮助类ActionCreator来封装Dispatcher,并提供便捷的方法来分发View中产生的事件,消息的传递通过Action(Action是一个普通的POJO类)来封装。

当用户点击UI上某个按钮的时候,一个完整的流程是这样的:按钮被点击触发回调方法,在回调方法中调用ActionCreator提供的有语义的的方法,ActionCreator会根据传入参数创建Action并通过Dispatcher发送给Store,所有订阅了这个Action的Store会接收到订阅的Action并消化Action,然后Store会发送UI状态改变的事件给相关的Activity(或Fragment),Activity在收到状态发生改变的事件之后,开始更新UI(更新UI的过程中会从Store获取所有需要的数据)。

Store的设计是很精巧的(比较类似PresentationModel模式),每一个Store仅仅负责一片逻辑相关的UI区域,用来维护这片UI的状态,比如有一个设置界面,它有有很多设置项,那么可以让它对应一个SettingStore,这个Store仅仅用来维护Setting的状态。Store对外仅仅提供get方法,它的更新通过Dispatcher派发的Action来更新,当有新的Action进来的时候,它会负责处理Action,并转化成UI需要的数据。


Holloworld示例

.├── MainActivity.java├── actions│   ├── Action.java│   ├── ActionsCreator.java│   └── MessageAction.java├── dispatcher│   └── Dispatcher.java├── model│   └── Message.java└── stores    ├── MessageStore.java    └── Store.java

这里包含4个目录和一个文件:

MainActivity.java Flux框架中的Controller-View部分,在Android中可以是Activity或者Fragment
actions Flux框架中的Action部分,存放不同类型的XXXAction.java和ActionsCreator.java文件
dispatcher Flux框架中的Dispatcher部分,存放 Dispatcher.java 文件,一个应用中只需要一个Dispatcher
model 存放各种业务逻辑相关的Model文件
stores Flux框架中的Stores部分,存在各种类型的 XXXStore.java 文件。

在AndroidFlux中Dispatcher是就是一个发布-订阅模式。Store会在这里注册自己的回调接口,Dispatcher会把Action分发到注册的Store,所以它会提供一些公有方法来注册监听和分发消息。

    /**     * Flux的Dispatcher模块     * Created by ntop on 18/12/15.     */    public class Dispatcher {        private static Dispatcher instance;        private final List<Store> stores = new ArrayList<>();        public static Dispatcher get() {            if (instance == null) {                instance = new Dispatcher();            }            return instance;        }        Dispatcher() {}        public void register(final Store store) {            stores.add(store);        }        public void unregister(final Store store) {            stores.remove(store);        }        public void dispatch(Action action) {            post(action);        }        private void post(final Action action) {            for (Store store : stores) {                store.onAction(action);            }        }    }

Dispatcher对外仅暴露3个公有方法:

register(final Store store) 用来注册每个Store的回调接口
unregister(final Store store) 用来接触Store的回调接口
dispatch(Action action) 用来触发Store注册的回调接口
这里仅仅用一个ArrayList来管理Stores,对于一个更复杂的App可能需要精心设计数据结构来管理Stores组织和相互间的依赖关系。

创建Stores

这里使用EventBus来实现Store,EventBus的主要功能是用来给Controller-View发送change事件:

/** * Flux的Store模块 * Created by ntop on 18/12/15. */public abstract class Store {    private  static final Bus bus = new Bus();    protected Store() {    }    public void register(final Object view) {        this.bus.register(view);    }    public void unregister(final Object view) {        this.bus.unregister(view);    }    void emitStoreChange() {        this.bus.post(changeEvent());    }    public abstract StoreChangeEvent changeEvent();    public abstract void onAction(Action action);    public class StoreChangeEvent {}}

抽象的Store类,提供了一个主要的虚方法 void onAction(Action action) ,这个方法是注册在Dispatcher里面的回调接口,当Dispatcher有数据派发过来的时候,可以在这里处理。

下面看一下更具体的和业务相关的MessageStore类:

/** * MessageStore类主要用来维护MainActivity的UI状态 * Created by ntop on 18/12/15. */public class MessageStore extends Store {    private static MessageStore singleton;    private Message mMessage = new Message();    public MessageStore() {        super();    }    public String getMessage() {        return mMessage.getMessage();    }    @Override    @Subscribe    public void onAction(Action action) {        switch (action.getType()) {            case MessageAction.ACTION_NEW_MESSAGE:                mMessage.setMessage((String) action.getData());                break;            default:        }        emitStoreChange();    }    @Override    public StoreChangeEvent changeEvent() {        return new StoreChangeEvent();    }}

在这里实现了 onAction(Action action) 方法,并用一个switch语句来路由各种不同的Action类型。同时维护了一个结构 Message.java 类,这个类用来记录当前要显示的消息。Store类只能通过Dispatcher来更新(不要提供setter方法),对外仅暴露各种getter方法来获取UI状态。这里用String getMessage()方法来获取具体的消息。

在Controller-View里面处理“change”事件

在Android中,Flux的Controller-View对应于Activity或者Fragment,我们需要在这里注册Strore发生改变的事件通知,以便在Store变化的时候重新绘制UI。

/** * Flux的Controller-View模块 * Created by ntop on 18/12/15. */public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private EditText vMessageEditor;    private Button vMessageButton;    private TextView vMessageView;    private Dispatcher dispatcher;    private ActionsCreator actionsCreator;    private MessageStore store;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initDependencies();        setupView();    }    @Override    protected void onDestroy() {        super.onDestroy();        dispatcher.unregister(store);    }    private void initDependencies() {        dispatcher = Dispatcher.get();        actionsCreator = ActionsCreator.get(dispatcher);        store = new MessageStore();        dispatcher.register(store);    }    private void setupView() {        vMessageEditor = (EditText) findViewById(R.id.message_editor);        vMessageView = (TextView) findViewById(R.id.message_view);        vMessageButton = (Button) findViewById(R.id.message_button);        vMessageButton.setOnClickListener(this);    }    @Override    public void onClick(View view) {        int id = view.getId();        if (id == R.id.message_button) {            if (vMessageEditor.getText() != null) {                actionsCreator.sendMessage(vMessageEditor.getText().toString());                vMessageEditor.setText(null);            }        }    }    private void render(MessageStore store) {        vMessageView.setText(store.getMessage());    }    @Override    protected void onResume() {        super.onResume();        store.register(this);    }    @Override    protected void onPause() {        super.onPause();        store.unregister(this);    }    @Subscribe    public void onStoreChange(Store.StoreChangeEvent event) {        render(store);    }}

这部分的代码比较多,首先在 onCreatre(…) 方法中初始化了依赖和需要的UI组件。最重要的是 onStoreChange(…) 方法,这个方法是注册在Store中回调(使用EventBus的@Subscribe注解标识),当Store发生变化的时候会触发这个方法,我们在这里调用render()方法重绘整个界面。

创建Action

Action是简单的POJO类型,只提供两个字段:type 和 data, 分别记录Action的类型和数据。注意Action一旦创建是不可更改的,
所以它的字段类型修饰为final类型。

public class Action<T> {    private final String type;    private final T data;    Action(String type, T data) {        this.type = type;        this.data = data;    }    public String getType() {        return type;    }    public T getData() {        return data;    }}

下面是一个业务相关的Action实现:

public class MessageAction extends Action<String> {    public static final String ACTION_NEW_MESSAGE = "new_message";    MessageAction(String type, String data) {        super(type, data);    }}

这个实现非常简单,仅仅多定义了一个Action类型字段:public static final String ACTION_NEW_MESSAGE = “new_message”。如你所见,Action都是这么简单的,不包含任何业务逻辑。

创建ActionCreator

ActionCreator 是Flux架构中第“四”个最重要的模块(前三:Dispatcher、Store、View),这里实际上处理很多工作,提供有一个有语义的API,构建Action,处理网络请求等。

/** * Flux的ActionCreator模块 * Created by ntop on 18/12/15. */public class ActionsCreator {    private static ActionsCreator instance;    final Dispatcher dispatcher;    ActionsCreator(Dispatcher dispatcher) {        this.dispatcher = dispatcher;    }    public static ActionsCreator get(Dispatcher dispatcher) {        if (instance == null) {            instance = new ActionsCreator(dispatcher);        }        return instance;    }    public void sendMessage(String message) {        dispatcher.dispatch(new MessageAction(MessageAction.ACTION_NEW_MESSAGE, message));    }}

此处提供了一个 sendMessage(String message) ,就像名字暗示的那样,这个方法用来发送消息(到Store)。在方法内部,会创建一个MessageAction来封装数据和Action类型,并通过Dispatcher发送到Store。

Model

无论是基于哪种框架的应用都需要Model模块,在这个简单的“HelloWorld”应用中,其实用一个String即可传递消息,但是为了架构的完整和更好的语义表达,定义一个Message类型封装一个String字段作为Model。

原创粉丝点击