├── .gitignore
├── AndroidFlux.iml
├── README.md
├── app
├── .gitignore
├── app.iml
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── flux
│ │ └── android
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── flux
│ │ │ └── android
│ │ │ ├── MainActivity.java
│ │ │ ├── actions
│ │ │ ├── Action.java
│ │ │ ├── ActionsCreator.java
│ │ │ └── MessageAction.java
│ │ │ ├── dispatcher
│ │ │ └── Dispatcher.java
│ │ │ ├── model
│ │ │ └── Message.java
│ │ │ └── stores
│ │ │ ├── MessageStore.java
│ │ │ └── Store.java
│ └── res
│ │ ├── drawable
│ │ └── flux_logo.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── values-v21
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── flux
│ └── android
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | .idea
3 | /gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | gradlew
11 | gradlew.bat
12 |
--------------------------------------------------------------------------------
/AndroidFlux.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 这是一个极简的HelloWorld应用,主要用来展示如何在Android平台架构Flux应用。并提供一些基础代码,方便开发者直接Copy这些代码到自己的工程中,省掉重新造轮子的过程。接下来会一步步的解释这个应用是如何构建的。
2 |
3 | *Demo程序是用AndroidStudio开发的,假设你已经了解Android和AndroidStudioIDE,如果你已经很熟悉Android应用的开发,看完[AndroidFlux一览](http://androidflux.github.io/docs/overview.html#content)或许已经可以开发出基于Flux框架的应用,如果你并不熟悉Flux或者Android,务必先读完这篇文档*
4 |
5 | ## 源码结构
6 |
7 | 本着架构即目录的思想,让我们先看一下源码结构,整个的源码结构是这样的:
8 |
9 | ```
10 | ➜ tree .
11 | .
12 | ├── MainActivity.java
13 | ├── actions
14 | │ ├── Action.java
15 | │ ├── ActionsCreator.java
16 | │ └── MessageAction.java
17 | ├── dispatcher
18 | │ └── Dispatcher.java
19 | ├── model
20 | │ └── Message.java
21 | └── stores
22 | ├── MessageStore.java
23 | └── Store.java
24 | ```
25 |
26 | 这里包含4个目录和一个文件:
27 |
28 | 1. MainActivity.java Flux框架中的Controller-View部分,在Android中可以是Activity或者Fragment
29 | 2. actions Flux框架中的Action部分,存放不同类型的`XXXAction.java`和`ActionsCreator.java`文件
30 | 3. dispatcher Flux框架中的Dispatcher部分,存放 `Dispatcher.java` 文件,一个应用中只需要一个Dispatcher
31 | 4. model 存放各种业务逻辑相关的Model文件
32 | 5. stores Flux框架中的Stores部分,存在各种类型的 `XXXStore.java` 文件
33 |
34 | ## 创建一个Dispatcher
35 |
36 | 在AndroidFlux中Dispatcher是就是一个发布-订阅模式。Store会在这里注册自己的回调接口,Dispatcher会把Action分发到注册的Store,所以它会提供一些公有方法来注册监听和分发消息。
37 | ```
38 | /**
39 | * Flux的Dispatcher模块
40 | * Created by ntop on 18/12/15.
41 | */
42 | public class Dispatcher {
43 | private static Dispatcher instance;
44 | private final List stores = new ArrayList<>();
45 |
46 | public static Dispatcher get() {
47 | if (instance == null) {
48 | instance = new Dispatcher();
49 | }
50 | return instance;
51 | }
52 |
53 | Dispatcher() {}
54 |
55 | public void register(final Store store) {
56 | stores.add(store);
57 | }
58 |
59 | public void unregister(final Store store) {
60 | stores.remove(store);
61 | }
62 |
63 | public void dispatch(Action action) {
64 | post(action);
65 | }
66 |
67 | private void post(final Action action) {
68 | for (Store store : stores) {
69 | store.onAction(action);
70 | }
71 | }
72 | }
73 | ```
74 | Dispatcher对外仅暴露3个公有方法:
75 |
76 | 1. register(final Store store) 用来注册每个Store的回调接口
77 | 2. unregister(final Store store) 用来接触Store的回调接口
78 | 3. dispatch(Action action) 用来触发Store注册的回调接口
79 |
80 | 这里仅仅用一个`ArrayList`来管理Stores,对于一个更复杂的App可能需要精心设计数据结构来管理Stores组织和相互间的依赖关系。
81 |
82 | ## 创建Stores
83 |
84 | 这里使用[EventBus](http://square.github.io/otto/)来实现Store,EventBus的主要功能是用来给Controller-View发送`change`事件:
85 | ```
86 | /**
87 | * Flux的Store模块
88 | * Created by ntop on 18/12/15.
89 | */
90 | public abstract class Store {
91 | private static final Bus bus = new Bus();
92 |
93 | protected Store() {
94 | }
95 |
96 | public void register(final Object view) {
97 | this.bus.register(view);
98 | }
99 |
100 | public void unregister(final Object view) {
101 | this.bus.unregister(view);
102 | }
103 |
104 | void emitStoreChange() {
105 | this.bus.post(changeEvent());
106 | }
107 |
108 | public abstract StoreChangeEvent changeEvent();
109 | public abstract void onAction(Action action);
110 |
111 | public class StoreChangeEvent {}
112 | }
113 | ```
114 | 抽象的Store类,提供了一个主要的虚方法 `void onAction(Action action)` ,这个方法是注册在Dispatcher里面的回调接口,当Dispatcher有数据派发过来的时候,可以在这里处理。
115 |
116 | 下面看一下更具体的和业务相关的MessageStore类:
117 |
118 | ```
119 | /**
120 | * MessageStore类主要用来维护MainActivity的UI状态
121 | * Created by ntop on 18/12/15.
122 | */
123 | public class MessageStore extends Store {
124 | private static MessageStore singleton;
125 | private Message mMessage = new Message();
126 |
127 | public MessageStore() {
128 | super();
129 | }
130 |
131 | public String getMessage() {
132 | return mMessage.getMessage();
133 | }
134 |
135 | @Override
136 | @Subscribe
137 | public void onAction(Action action) {
138 | switch (action.getType()) {
139 | case MessageAction.ACTION_NEW_MESSAGE:
140 | mMessage.setMessage((String) action.getData());
141 | break;
142 | default:
143 | }
144 | emitStoreChange();
145 | }
146 |
147 |
148 | @Override
149 | public StoreChangeEvent changeEvent() {
150 | return new StoreChangeEvent();
151 | }
152 | }
153 | ```
154 |
155 | 在这里实现了 `onAction(Action action)` 方法,并用一个`switch`语句来路由各种不同的Action类型。同时维护了一个结构 `Message.java` 类,这个类用来记录当前要显示的消息。Store类只能通过Dispatcher来更新(不要提供`setter`方法),对外仅暴露各种`getter`方法来获取UI状态。这里用`String getMessage()`方法来获取具体的消息。
156 |
157 | ## 在Controller-View里面处理“change”事件
158 |
159 | 在Android中,Flux的Controller-View对应于Activity或者Fragment,我们需要在这里注册Strore发生改变的事件通知,以便在Store变化的时候重新绘制UI。
160 |
161 | ```
162 | /**
163 | * Flux的Controller-View模块
164 | * Created by ntop on 18/12/15.
165 | */
166 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
167 | private EditText vMessageEditor;
168 | private Button vMessageButton;
169 | private TextView vMessageView;
170 |
171 | private Dispatcher dispatcher;
172 | private ActionsCreator actionsCreator;
173 | private MessageStore store;
174 |
175 | @Override
176 | protected void onCreate(Bundle savedInstanceState) {
177 | super.onCreate(savedInstanceState);
178 | setContentView(R.layout.activity_main);
179 | initDependencies();
180 | setupView();
181 | }
182 |
183 | @Override
184 | protected void onDestroy() {
185 | super.onDestroy();
186 | dispatcher.unregister(store);
187 | }
188 |
189 | private void initDependencies() {
190 | dispatcher = Dispatcher.get();
191 | actionsCreator = ActionsCreator.get(dispatcher);
192 | store = new MessageStore();
193 | dispatcher.register(store);
194 | }
195 |
196 | private void setupView() {
197 | vMessageEditor = (EditText) findViewById(R.id.message_editor);
198 | vMessageView = (TextView) findViewById(R.id.message_view);
199 | vMessageButton = (Button) findViewById(R.id.message_button);
200 | vMessageButton.setOnClickListener(this);
201 | }
202 |
203 | @Override
204 | public void onClick(View view) {
205 | int id = view.getId();
206 | if (id == R.id.message_button) {
207 | if (vMessageEditor.getText() != null) {
208 | actionsCreator.sendMessage(vMessageEditor.getText().toString());
209 | vMessageEditor.setText(null);
210 | }
211 | }
212 | }
213 |
214 | private void render(MessageStore store) {
215 | vMessageView.setText(store.getMessage());
216 | }
217 |
218 | @Override
219 | protected void onResume() {
220 | super.onResume();
221 | store.register(this);
222 | }
223 |
224 | @Override
225 | protected void onPause() {
226 | super.onPause();
227 | store.unregister(this);
228 | }
229 |
230 | @Subscribe
231 | public void onStoreChange(Store.StoreChangeEvent event) {
232 | render(store);
233 | }
234 | }
235 | ```
236 |
237 | 这部分的代码比较多,首先在 `onCreatre(...)` 方法中初始化了依赖和需要的UI组件。最重要的是 `onStoreChange(...)` 方法,这个方法是注册在Store中回调(使用EventBus的`@Subscribe`注解标识),当Store发生变化的时候会触发这个方法,我们在这里调用`render()`方法重绘整个界面。
238 |
239 | ## 创建Action
240 |
241 | Action是简单的POJO类型,只提供两个字段:`type` 和 `data`, 分别记录Action的类型和数据。注意Action一旦创建是不可更改的,
242 | 所以它的字段类型修饰为`final`类型。
243 |
244 | ```
245 | public class Action {
246 | private final String type;
247 | private final T data;
248 |
249 | Action(String type, T data) {
250 | this.type = type;
251 | this.data = data;
252 | }
253 |
254 | public String getType() {
255 | return type;
256 | }
257 |
258 | public T getData() {
259 | return data;
260 | }
261 | }
262 | ```
263 | 下面是一个业务相关的Action实现:
264 |
265 | ```
266 | public class MessageAction extends Action {
267 | public static final String ACTION_NEW_MESSAGE = "new_message";
268 |
269 | MessageAction(String type, String data) {
270 | super(type, data);
271 | }
272 | }
273 | ```
274 |
275 | 这个实现非常简单,仅仅多定义了一个Action类型字段:`public static final String ACTION_NEW_MESSAGE = "new_message"`。如你所见,Action都是这么简单的,不包含任何业务逻辑。
276 |
277 | ## 创建ActionCreator
278 |
279 | ActionCreator 是Flux架构中第“四”个最重要的模块(前三:Dispatcher、Store、View),这里实际上处理很多工作,提供有一个有语义的API,构建Action,处理网络请求等。
280 |
281 | ```
282 | /**
283 | * Flux的ActionCreator模块
284 | * Created by ntop on 18/12/15.
285 | */
286 | public class ActionsCreator {
287 |
288 | private static ActionsCreator instance;
289 | final Dispatcher dispatcher;
290 |
291 | ActionsCreator(Dispatcher dispatcher) {
292 | this.dispatcher = dispatcher;
293 | }
294 |
295 | public static ActionsCreator get(Dispatcher dispatcher) {
296 | if (instance == null) {
297 | instance = new ActionsCreator(dispatcher);
298 | }
299 | return instance;
300 | }
301 |
302 | public void sendMessage(String message) {
303 | dispatcher.dispatch(new MessageAction(MessageAction.ACTION_NEW_MESSAGE, message));
304 | }
305 | }
306 | ```
307 | 此处提供了一个 `sendMessage(String message)` ,就像名字暗示的那样,这个方法用来发送消息(到Store)。在方法内部,会创建一个`MessageAction`来封装数据和Action类型,并通过Dispatcher发送到Store。
308 |
309 | ## Model
310 | 无论是基于哪种框架的应用都需要Model模块,在这个简单的“HelloWorld”应用中,其实用一个String即可传递消息,但是为了架构的完整和更好的语义表达,定义一个Message类型封装一个String字段作为Model。
311 |
312 | 希望通过这个简单的HelloWorld应用,能够让你一窥Flux的面貌。如果你想更深入的了解在Android平台上应用Flux架构,可以查看我们的[Github站点](http://androidflux.github.io/)。
313 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.example.flux.android"
9 | minSdkVersion 15
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:22.2.0'
26 | compile 'com.android.support:design:22.2.0'
27 | compile 'com.squareup:otto:1.3.8'
28 | }
29 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/ntop/Tools/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/flux/android/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/flux/android/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.view.View;
6 | import android.widget.Button;
7 | import android.widget.EditText;
8 | import android.widget.TextView;
9 |
10 | import com.example.flux.android.stores.Store;
11 | import com.squareup.otto.Bus;
12 | import com.squareup.otto.Subscribe;
13 |
14 | import com.example.flux.android.actions.ActionsCreator;
15 | import com.example.flux.android.dispatcher.Dispatcher;
16 | import com.example.flux.android.stores.MessageStore;
17 |
18 | /**
19 | * Flux的Controller-View模块
20 | * Created by ntop on 18/12/15.
21 | */
22 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
23 | private EditText vMessageEditor;
24 | private Button vMessageButton;
25 | private TextView vMessageView;
26 |
27 | private Dispatcher dispatcher;
28 | private ActionsCreator actionsCreator;
29 | private MessageStore store;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_main);
35 | initDependencies();
36 | setupView();
37 | }
38 |
39 | @Override
40 | protected void onDestroy() {
41 | super.onDestroy();
42 | dispatcher.unregister(store);
43 | }
44 |
45 | private void initDependencies() {
46 | dispatcher = Dispatcher.get();
47 | actionsCreator = ActionsCreator.get(dispatcher);
48 | store = new MessageStore();
49 | dispatcher.register(store);
50 | }
51 |
52 | private void setupView() {
53 | vMessageEditor = (EditText) findViewById(R.id.message_editor);
54 | vMessageView = (TextView) findViewById(R.id.message_view);
55 | vMessageButton = (Button) findViewById(R.id.message_button);
56 | vMessageButton.setOnClickListener(this);
57 | }
58 |
59 | @Override
60 | public void onClick(View view) {
61 | int id = view.getId();
62 | if (id == R.id.message_button) {
63 | if (vMessageEditor.getText() != null) {
64 | actionsCreator.sendMessage(vMessageEditor.getText().toString());
65 | vMessageEditor.setText(null);
66 | }
67 | }
68 | }
69 |
70 | private void render(MessageStore store) {
71 | vMessageView.setText(store.getMessage());
72 | }
73 |
74 | @Override
75 | protected void onResume() {
76 | super.onResume();
77 | store.register(this);
78 | }
79 |
80 | @Override
81 | protected void onPause() {
82 | super.onPause();
83 | store.unregister(this);
84 | }
85 |
86 | @Subscribe
87 | public void onStoreChange(Store.StoreChangeEvent event) {
88 | render(store);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/flux/android/actions/Action.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android.actions;
2 |
3 | /**
4 | * Created by ntop on 18/12/15.
5 | */
6 | public class Action {
7 | private final String type;
8 | private final T data;
9 |
10 | Action(String type, T data) {
11 | this.type = type;
12 | this.data = data;
13 | }
14 |
15 | public String getType() {
16 | return type;
17 | }
18 |
19 | public T getData() {
20 | return data;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/flux/android/actions/ActionsCreator.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android.actions;
2 |
3 | import com.example.flux.android.dispatcher.Dispatcher;
4 |
5 | /**
6 | * Flux的ActionCreator模块
7 | * Created by ntop on 18/12/15.
8 | */
9 | public class ActionsCreator {
10 |
11 | private static ActionsCreator instance;
12 | final Dispatcher dispatcher;
13 |
14 | ActionsCreator(Dispatcher dispatcher) {
15 | this.dispatcher = dispatcher;
16 | }
17 |
18 | public static ActionsCreator get(Dispatcher dispatcher) {
19 | if (instance == null) {
20 | instance = new ActionsCreator(dispatcher);
21 | }
22 | return instance;
23 | }
24 |
25 | public void sendMessage(String message) {
26 | dispatcher.dispatch(new MessageAction(MessageAction.ACTION_NEW_MESSAGE, message));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/flux/android/actions/MessageAction.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android.actions;
2 |
3 | /**
4 | * Created by ntop on 18/12/15.
5 | */
6 | public class MessageAction extends Action {
7 | public static final String ACTION_NEW_MESSAGE = "new_message";
8 |
9 | MessageAction(String type, String data) {
10 | super(type, data);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/flux/android/dispatcher/Dispatcher.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android.dispatcher;
2 |
3 | import com.example.flux.android.actions.Action;
4 | import com.example.flux.android.stores.Store;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;;
8 |
9 | /**
10 | * Flux的Dispatcher模块
11 | * Created by ntop on 18/12/15.
12 | */
13 | public class Dispatcher {
14 | private static Dispatcher instance;
15 | private final List stores = new ArrayList<>();
16 |
17 | public static Dispatcher get() {
18 | if (instance == null) {
19 | instance = new Dispatcher();
20 | }
21 | return instance;
22 | }
23 |
24 | Dispatcher() {}
25 |
26 | public void register(final Store store) {
27 | if (!stores.contains(store)) {
28 | stores.add(store);
29 | }
30 | }
31 |
32 | public void unregister(final Store store) {
33 | stores.remove(store);
34 | }
35 |
36 | public void dispatch(Action action) {
37 | post(action);
38 | }
39 |
40 | private void post(final Action action) {
41 | for (Store store : stores) {
42 | store.onAction(action);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/flux/android/model/Message.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android.model;
2 |
3 | /**
4 | * Created by ntop on 18/12/15.
5 | */
6 | public class Message {
7 | private String mText;
8 |
9 | public Message(){}
10 |
11 | public Message(String text) {
12 | mText = text;
13 | }
14 |
15 | public String getMessage() {
16 | return mText;
17 | }
18 |
19 | public void setMessage(String text) {
20 | mText = text;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/flux/android/stores/MessageStore.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android.stores;
2 |
3 | import com.example.flux.android.actions.Action;
4 | import com.example.flux.android.actions.MessageAction;
5 | import com.example.flux.android.model.Message;
6 | import com.squareup.otto.Bus;
7 | import com.squareup.otto.Subscribe;
8 |
9 | /**
10 | * MessageStore类主要用来维护MainActivity的UI状态
11 | * Created by ntop on 18/12/15.
12 | */
13 | public class MessageStore extends Store {
14 | private static MessageStore singleton;
15 | private Message mMessage = new Message();
16 |
17 | public MessageStore() {
18 | super();
19 | }
20 |
21 | public String getMessage() {
22 | return mMessage.getMessage();
23 | }
24 |
25 | @Override
26 | @Subscribe
27 | public void onAction(Action action) {
28 | switch (action.getType()) {
29 | case MessageAction.ACTION_NEW_MESSAGE:
30 | mMessage.setMessage((String) action.getData());
31 | break;
32 | default:
33 | }
34 | emitStoreChange();
35 | }
36 |
37 |
38 | @Override
39 | public StoreChangeEvent changeEvent() {
40 | return new StoreChangeEvent();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/flux/android/stores/Store.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android.stores;
2 |
3 | import com.example.flux.android.actions.Action;
4 | import com.example.flux.android.dispatcher.Dispatcher;
5 | import com.squareup.otto.Bus;
6 |
7 | /**
8 | * Flux的Store模块
9 | * Created by ntop on 18/12/15.
10 | */
11 | public abstract class Store {
12 | private static final Bus bus = new Bus();
13 |
14 | protected Store() {
15 | }
16 |
17 | public void register(final Object view) {
18 | this.bus.register(view);
19 | }
20 |
21 | public void unregister(final Object view) {
22 | this.bus.unregister(view);
23 | }
24 |
25 | void emitStoreChange() {
26 | this.bus.post(changeEvent());
27 | }
28 |
29 | public abstract StoreChangeEvent changeEvent();
30 | public abstract void onAction(Action action);
31 |
32 | public class StoreChangeEvent {}
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/flux_logo.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
17 |
24 |
25 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 | >
2 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidFlux
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/flux/android/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.flux.android;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.5.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------