Android-architecture之MVC、MVP、MVVM、Data-Binding

传送门

这里是之前分享的关于Android架构的一篇ppt,可以作为简要的参考
Android Architecture(Is Activity God?)

MVC

结构简介

各个模块的关系以及功能
这里写图片描述
这里写图片描述

实例分析

这里写图片描述

Controller控制器式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
94
95
96
97
98
public class MainActivity extends ActionBarActivity implements OnWeatherListener, View.OnClickListener {
private WeatherModel weatherModel;
private Dialog loadingDialog;
private EditText cityNOInput;
private TextView city;
private TextView cityNO;
private TextView temp;
private TextView wd;
private TextView ws;
private TextView sd;
private TextView wse;
private TextView time;
private TextView njd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
weatherModel = new WeatherModelImpl();
initView();
}
/**
* 初始化View
*/
private void initView() {
cityNOInput = findView(R.id.et_city_no);
city = findView(R.id.tv_city);
cityNO = findView(R.id.tv_city_no);
temp = findView(R.id.tv_temp);
wd = findView(R.id.tv_WD);
ws = findView(R.id.tv_WS);
sd = findView(R.id.tv_SD);
wse = findView(R.id.tv_WSE);
time = findView(R.id.tv_time);
njd = findView(R.id.tv_njd);
findView(R.id.btn_go).setOnClickListener(this);
loadingDialog = new ProgressDialog(this);
loadingDialog.setTitle(加载天气中...);
}
/**
* 显示结果
*
* @param weather
*/
public void displayResult(Weather weather) {
WeatherInfo weatherInfo = weather.getWeatherinfo();
city.setText(weatherInfo.getCity());
cityNO.setText(weatherInfo.getCityid());
temp.setText(weatherInfo.getTemp());
wd.setText(weatherInfo.getWD());
ws.setText(weatherInfo.getWS());
sd.setText(weatherInfo.getSD());
wse.setText(weatherInfo.getWSE());
time.setText(weatherInfo.getTime());
njd.setText(weatherInfo.getNjd());
}
/**
* 隐藏进度对话框
*/
public void hideLoadingDialog() {
loadingDialog.dismiss();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_go:
loadingDialog.show();
weatherModel.getWeather(cityNOInput.getText().toString().trim(), this);
break;
}
}
@Override
public void onSuccess(Weather weather) {
hideLoadingDialog();
displayResult(weather);
}
@Override
public void onError() {
hideLoadingDialog();
Toast.makeText(this, 获取天气信息失败, Toast.LENGTH_SHORT).show();
}
private T findView(int id) {
return (T) findViewById(id);
}
}
Model模型
1
2
3
public interface WeatherModel {
void getWeather(String cityNumber, OnWeatherListener listener);
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class WeatherModelImpl implements WeatherModel {
@Override
public void getWeather(String cityNumber, final OnWeatherListener listener) {
/*数据层操作*/
VolleyRequest.newInstance().newGsonRequest(http://www.weather.com.cn/data/sk/ + cityNumber + .html,
Weather.class, new Response.Listener() {
@Override
public void onResponse(Weather weather) {
if (weather != null) {
listener.onSuccess(weather);
} else {
listener.onError();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
listener.onError();
}
});
}


## 总结
> 扩展性好、维护性、模块职责明确
>
耦合性低(解耦)、V和M非真正意义上的分离

什么时候适合使用MVC设计模式?

当一个小的项目且无需频繁修改需求就不用MVC框架来设计了,那样反而觉得代码过度设计,代码臃肿。一般在大的项目中,且业务逻辑处理复杂,页面显示比较多,需要模块化设计的项目使用MVC就有足够的优势了。

MVP

结构简介

Drawing
这里写图片描述

为什么使用MVP模式

在Android开发中,Activity并不是一个标准的MVC模式中的Controller,它的首要职责是加载应用的布局和初始化用户界面,并接受并处理来自用户的操作请求,进而作出响应。随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。当我们将其中复杂的逻辑处理移至另外的一个类(Presneter)中时,Activity其实就是MVP模式中View,它负责UI元素的初始化,建立UI元素与Presenter的关联(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由Presenter处理).

另外,回想一下你在开发Android应用时是如何对代码逻辑进行单元测试的?是否每次都要将应用部署到Android模拟器或真机上,然后通过模拟用户操作进行测试?然而由于Android平台的特性,每次部署都耗费了大量的时间,这直接导致开发效率的降低。而在MVP模式中,处理复杂逻辑的Presenter是通过interface与View(Activity)进行交互的,这说明了什么?说明我们可以通过自定义类实现这个interface来模拟Activity的行为对Presenter进行单元测试,省去了大量的部署及测试的时间。

实例分析

MVP模式

View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。这就是MVP模式的整个核心过程。

官方模式图

android-architecture官方传送门
这里写图片描述

案例

这里以暴风体育中的话题列表为例来进行介绍:

这里写图片描述
这里写图片描述

TopicModel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public interface TopicModel {
/**
* 加载话题列表首页数据
*
* @param context
* @param listener
*/
void loadTopicList(Context context, TopicModelImpl.OnLoadTopicListListener listener);
/**
* 从本地数据库中获取我关注的话题数据
*
* @param context
* @param listener
* @return
*/
ArrayList<TopicItem> loadFollowTopic(Context context, TopicModelImpl.OnLoadTopicListListener listener);
/**
* 全部话题加载更多数据
*
* @param context
* @param paramMap
* @param listener
*/
void loadMoreAllTopic(Context context, Map<String, String> paramMap, TopicModelImpl.OnLoadTopicListListener listener);
/**
* 更新我关注的话题的最新帖子数和帖子最近的更新时间
*
* @param context
* @param threadItem
* @param listener
*/
void updateThreadItem(final Context context, ThreadItem threadItem, TopicModelImpl.OnLoadTopicListListener listener);
}
TopicPresenter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface TopicPresenter {
/**
* 加载话题列表首页数据
*
* @param context
*/
void loadTopicList(Context context);
/**
* 全部话题加载更多数据
*
* @param context
* @param paramMap
*/
void loadMoreAllTopic(Context context, Map<String, String> paramMap);
/**
*
* @param context
* @return
*/
ArrayList<TopicItem> loadFollowTopic(Context context);
}
TopicView
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface TopicView {
void showProgress();
void addTopics(List<TopicItem> topicList);
void addSwipeUpItem(SwipeUpItem item);
void addLoadMoreTopics(List<TopicItem> topicList);
void hideProgress();
void showLoadFailMsg();
//二次请求需要重新刷新界面
void notifyAdapter();
}
TopicModelImpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/**
* DES:
* Created by sushuai on 2016/4/13.
*/
public class TopicModelImpl implements TopicModel {
private static final String TAG = "TopicModelImpl";
/**
* 加载话题列表首页数据
*
* @param context
* @param listener
*/
@Override
public void loadTopicList(final Context context, final OnLoadTopicListListener listener) {
AsyncHttpRequest.doASynGetRequest(context, UrlContainer.HOME_TOPIC, null, true, new AsyncHttpRequest.CallBack() {
@Override
public void fail(String ret) {
listener.onFailure(Net.ErrorNo.NO_DATA);
}
@Override
public void call(String data) {
try {
ArrayList<TopicItem> items = (ArrayList<TopicItem>) TopicListDataParseUtils.readJsonTopicLists(data, listener);
//items.addAll(0, loadFollowTopic(context, listener));
if (items != null) {
listener.onSuccess(items);
}
} catch (JSONException e) {
e.printStackTrace();
listener.onFailure(Net.ErrorNo.ERROR_JSON);
}
}
});
}
/**
* 从本地数据库中获取我关注的话题数据
*
* @param context
* @param listener
* @return
*/
@Override
public ArrayList<TopicItem> loadFollowTopic(Context context, final OnLoadTopicListListener listener) {
ArrayList<TopicItem> items = new ArrayList<>();
ArrayList<ThreadItem> ThreadItems = (ArrayList<ThreadItem>) FollowTopicDao.getInstance(context).getLatest3Topics();
if (ThreadItems.size() <= 0) {
return items;
}
for (int i = 0; i < ThreadItems.size(); i++) {
ThreadItem threadItem = ThreadItems.get(i);
updateThreadItem(context, threadItem, listener);
}
TopicItem meItem = new TopicItem();
meItem.setType(TopicAdapter.TYPE_TOPIC_TITLE_ME);
items.add(meItem);
for (int i = 0; i < ThreadItems.size(); i++) {
TopicItem topicItem = new TopicItem();
topicItem.setType(TopicAdapter.TYPE_TOPIC_THREAD);
topicItem.setOther(ThreadItems.get(i));
items.add(topicItem);
}
return items;
}
/**
* 更新我关注的话题的最新帖子数和帖子最近的更新时间
*
* @param context
* @param threadItem
* @param listener
*/
@Override
public void updateThreadItem(final Context context, final ThreadItem threadItem, final OnLoadTopicListListener listener) {
Map<String, String> map = new HashMap<>();
map.put(Net.Field.id, String.valueOf(threadItem.getId()));
final int prePosts = threadItem.getCount();
AsyncHttpRequest.doASynGetRequest(context, UrlContainer.GET_TOPIC_POSTS, (HashMap<String, String>) map, true, new AsyncHttpRequest.CallBack() {
@Override
public void fail(String ret) {
}
@Override
public void call(String data) {
try {
JSONObject jo = new JSONObject(data);
int errno = DataParseUtils.getJsonInt(jo, Net.Field.errno);
if (errno == Net.ErrorNo.SUCCESS) {
JSONObject jsonObj = DataParseUtils.getJsonObj(jo, Net.Field.data);
int count = DataParseUtils.getJsonInt(jsonObj, Net.Field.count);
long latest_update_tm = DataParseUtils.getJsonLong(jsonObj, Net.Field.latest_update_tm);
threadItem.setUpdateCount(count - prePosts);
threadItem.setCount(count);
threadItem.setUpdateTime(latest_update_tm);
FollowTopicDao.getInstance(context).updatePostsById(threadItem.getId(), count);
listener.onUpdateThreadItem();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
/**
* 全部话题加载更多数据
*
* @param context
* @param paramMap
* @param listener
*/
@Override
public void loadMoreAllTopic(Context context, Map<String, String> paramMap, final OnLoadTopicListListener listener) {
AsyncHttpRequest.doASynGetRequest(context, UrlContainer.TOPIC_LIST, (HashMap<String, String>) paramMap, true, new AsyncHttpRequest.CallBack() {
@Override
public void fail(String ret) {
listener.onFailure(Net.ErrorNo.NO_DATA);
}
@Override
public void call(String data) {
try {
ArrayList<TopicItem> items = (ArrayList<TopicItem>) TopicListDataParseUtils.readMoreAllTopic(data, listener);
if (items != null) {
listener.onLoadMoreAllTopics(items);
}
} catch (JSONException e) {
e.printStackTrace();
listener.onFailure(Net.ErrorNo.ERROR_JSON);
}
}
});
}
public interface OnLoadTopicListListener {
//加载话题列表首页数据成功
void onSuccess(List<TopicItem> list);
//加载话题列表首页数据失败
void onFailure(int erroNo);
//全部话题加载更多相关配置
void onLoadMoreSwipeUp(SwipeUpItem item);
//回去加载更多数据
void onLoadMoreAllTopics(List<TopicItem> list);
//更新我关注的话题的相关数据
void onUpdateThreadItem();
}
}


TopicPresenterImpl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
/**
* DES:
* Created by sushuai on 2016/4/13.
*/
public class TopicPresenterImpl implements TopicPresenter, TopicModelImpl.OnLoadTopicListListener {
private static final String TAG = "TopicPresenterImpl";
private TopicModel mTopicModel;
private TopicView mTopicView;
public TopicPresenterImpl(TopicView topicView) {
this.mTopicModel = new TopicModelImpl();
this.mTopicView = topicView;
}
@Override
public void loadTopicList(Context context) {
mTopicModel.loadTopicList(context, this);
}
@Override
public void loadMoreAllTopic(Context context, Map<String, String> paramMap) {
mTopicModel.loadMoreAllTopic(context, paramMap, this);
}
@Override
public ArrayList<TopicItem> loadFollowTopic(Context context) {
return mTopicModel.loadFollowTopic(context,this);
}
@Override
public void onSuccess(List<TopicItem> list) {
mTopicView.hideProgress();
mTopicView.addTopics(list);
}
@Override
public void onFailure(int erroNo) {
mTopicView.hideProgress();
mTopicView.showLoadFailMsg();
}
@Override
public void onLoadMoreSwipeUp(SwipeUpItem item) {
mTopicView.addSwipeUpItem(item);
}
@Override
public void onLoadMoreAllTopics(List<TopicItem> list) {
mTopicView.addLoadMoreTopics(list);
}
@Override
public void onUpdateThreadItem() {
mTopicView.notifyAdapter();
}
}


TabTopicFragment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/**
* 话题
* SuShuai
* 2016/4/12 14:39
*/
public class TabTopicFragment extends BaseFragment implements TopicAdapter.AdapterCallback, TopicView, IHandlerMessage, XListView.IXListViewListener {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String TAG = "TabTopicFragment";
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private XListView listView;
private TopicAdapter topicAdapter;
private ArrayList<TopicItem> topicList = new ArrayList<>();
private ArrayList<TopicItem> homeList = new ArrayList<>();
private ArrayList<TopicItem> followTopicList = new ArrayList<>();
private TopicPresenter mTopicPresenter;
private CommonHandler<TabTopicFragment> handler;
private SwipeUpItem swipeUpItem;
private View rootView;
private String after = "";
public TabTopicFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment TabTopicFragment.
*/
// TODO: Rename and change types and number of parameters
public static TabTopicFragment newInstance(String param1, String param2) {
TabTopicFragment fragment = new TabTopicFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
LogHelper.e(TAG, "SuS--> onAttach: ");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
mTopicPresenter = new TopicPresenterImpl(this);
LogHelper.e(TAG, "SuS--> onCreate: ");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LogHelper.e(TAG, "whb--> onCreateView: ");
if (rootView == null) {
rootView = inflater.inflate(R.layout.fragment_tab_topic, container, false);
initViews(rootView);
}
return rootView;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
LogHelper.e(TAG, "SuS--> onActivityCreated: ");
super.onActivityCreated(savedInstanceState);
initData();
}
private void initData() {
handler = new CommonHandler<TabTopicFragment>(this);
topicAdapter = new TopicAdapter(getActivity(), this);
listView.setAdapter(topicAdapter);
if (NetUtils.isNetworkAvaliable(getActivity())) {
showLoadingView();
mTopicPresenter.loadTopicList(getActivity());
followTopicList = mTopicPresenter.loadFollowTopic(getActivity());
} else {
if (topicList.size() > 0) {
topicAdapter.update(topicList);
ToastUtils.toast(getActivity(), "没有网络");
listView.restListView();
return;
}
showNetErroView(R.string.tips_net_error);
}
}
private void initViews(View v) {
setImmerseLayout(v.findViewById(R.id.common_back));
setTitleBar(v, R.string.tab_topic);
setLeftGone(v);
listView = (XListView) v.findViewById(R.id.lv_topic);
listView.setPullRefreshEnable(true);
listView.setPullLoadEnable(true);
listView.setAutoLoadEnable(true);
listView.setXListViewListener(this);
}
@Override
public void onAdapterCallback(int eventId, Object obj) {
if (isAdded()) {
BaofengStatistics.onUmengEvent(getActivity(), BfCountConst.TopicConst.BBS_MOREFOLLOW_CLICK);
LogHelper.v("umeng", "bbs_morefollow_click 计数一次");
}
ActivityUtil.startActivity(getActivity(), MoreFollowTopicActivity.class, null, false);
}
@Override
public void showProgress() {
}
@Override
public void addTopics(List<TopicItem> topicList) {
handler.obtainMessage(HandlerMsg.MSG_LOAD_TOPIC_LIST_SUC,
topicList).sendToTarget();
}
@Override
public void addSwipeUpItem(SwipeUpItem item) {
if (item == null) {
return;
}
handler.obtainMessage(HandlerMsg.MSG_LOAD_SWIPE_UP_ITEM,
item).sendToTarget();
}
@Override
public void addLoadMoreTopics(List<TopicItem> topicList) {
handler.obtainMessage(HandlerMsg.MSG_LOAD_MORE_TOPICS,
topicList).sendToTarget();
}
@Override
public void hideProgress() {
// handler.obtainMessage(HandlerMsg.MSG_DISMISS_LOADING).sendToTarget();
}
@Override
public void showLoadFailMsg() {
if (topicList == null || topicList.size() == 0) {
handler.obtainMessage(HandlerMsg.MSG_SHOW_EMPTY_CONTENT).sendToTarget();
}else {
handler.obtainMessage(HandlerMsg.MSG_SHOW_FAIL).sendToTarget();
}
}
@Override
public void notifyAdapter() {
handler.obtainMessage(HandlerMsg.MSG_NOTIFY_ADAPTER_CONTENT).sendToTarget();
}
@Override
public void handlerCallback(Message msg) {
switch (msg.what) {
case HandlerMsg.MSG_LOAD_TOPIC_LIST_SUC:
dealTopicListSuc(msg);
break;
case HandlerMsg.MSG_LOAD_SWIPE_UP_ITEM:
SwipeUpItem item = (SwipeUpItem) msg.obj;
this.swipeUpItem = item;
break;
case HandlerMsg.MSG_LOAD_MORE_TOPICS:
dealLoadMoreTopics(msg);
break;
case HandlerMsg.MSG_DISMISS_LOADING:
dismissLoadingView();
break;
case HandlerMsg.MSG_SHOW_EMPTY_CONTENT:
showContentEmptyView();
break;
case HandlerMsg.MSG_NOTIFY_ADAPTER_CONTENT:
topicAdapter.notifyDataSetChanged();
break;
case HandlerMsg.MSG_SHOW_FAIL:
ToastUtils.toast(getActivity(),R.string.error_no);
break;
default:
break;
}
}
private void dealLoadMoreTopics(Message msg) {
List<TopicItem> moreList = (List<TopicItem>) msg.obj;
int count1 = listView.getLastVisiblePosition();
int count2 = topicAdapter.getCount()-1+2;
if (moreList.size() < swipeUpItem.getLimit() && count1 == count2) {
ToastUtils.toast(getActivity(), "已到达底部");
}
if (moreList.size() > 0) {
after = TabTopicUtil.getLastKey(moreList);
}
TabTopicUtil.filterDuplicatedTopic(moreList,homeList);
this.topicList.addAll(moreList);
topicAdapter.update(this.topicList);
listView.restListView();
}
private void dealTopicListSuc(Message msg) {
List<TopicItem> topicList = (List<TopicItem>) msg.obj;
if (topicList.size() <= 0) {
showContentEmptyView();
return;
}
after = TabTopicUtil.getLastKey(topicList);
TabTopicUtil.removeDuplicateWithOrder(topicList);
topicList.addAll(0,followTopicList);
this.topicList = (ArrayList<TopicItem>) topicList;
this.homeList = (ArrayList<TopicItem>) topicList;
topicAdapter.update(topicList);
dismissLoadingView();
listView.restListView();
}
@Override
public void onRefresh() {
//handler.postDelayed(new Runnable() {
// @Override
//public void run() {
if (NetUtils.isNetworkAvaliable(getActivity())) {
mTopicPresenter.loadTopicList(getActivity());
} else {
if (topicList.size() > 0) {
ToastUtils.toast(getActivity(), "没有网络");
listView.restListView();
return;
}
showNetErroView(R.string.tips_net_error);
}
// }
//}, 2000);
}
@Override
public void onLoadMore() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
Map<String, String> m = new HashMap<>();
int size = topicList.size();
if (size <= 0)
return;
m.put(Net.Param.ID, String.valueOf(swipeUpItem.getId()));
m.put(Net.Param.AFTER, after);
m.put(Net.Param.LIMIT, String.valueOf(swipeUpItem.getLimit()));
if (NetUtils.isNetworkAvaliable(getActivity())) {
mTopicPresenter.loadMoreAllTopic(getActivity(), m);
} else {
ToastUtils.toast(getActivity(), "没有网络");
listView.restListView();
}
}
}, 500);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.fragment_net_error_subTree:
reQuestData();
break;
default:
break;
}
}
/**
* 重新请求数据
*/
private void reQuestData() {
dismissNetErroView();
dismissContentEmptyView();
if (NetUtils.isNetworkAvaliable(getActivity())) {
showLoadingView();
mTopicPresenter.loadTopicList(getActivity());
} else {
showNetErroView(R.string.tips_net_error);
}
}
public interface HandlerMsg {
//获取话题列表成功
int MSG_LOAD_TOPIC_LIST_SUC = 2002;
//获取加载更多配置选项
int MSG_LOAD_SWIPE_UP_ITEM = 2003;
//加载更多话题
int MSG_LOAD_MORE_TOPICS = 2004;
//隐藏loading
int MSG_DISMISS_LOADING = 2005;
//显示空
int MSG_SHOW_EMPTY_CONTENT = 2006;
//二次请求刷新界面
int MSG_NOTIFY_ADAPTER_CONTENT = 2007;
//显示失败
int MSG_SHOW_FAIL = 2008;
}
@Override
public void onDestroyView() {
// unbindDrawables(getView());
LogHelper.e(TAG, "whb--> onDestroyView: ");
super.onDestroyView();
}
@Override
public void onResume() {
super.onResume();
LogHelper.d(TAG, "SuS--> onResume: ");
BaofengStatistics.onUmengEvent(getActivity(), BfCountConst.TopicConst.BBS_CHANNELLIST_SHOW);
LogHelper.v("umeng", "bbs_channelList_show 计数一次");
topicList.removeAll(followTopicList);
followTopicList = mTopicPresenter.loadFollowTopic(getActivity());
topicList.addAll(0,followTopicList);
topicAdapter.notifyDataSetChanged();
//initData();
}
}


## MVP与MVC的异同
MVC模式与MVP模式都作为用来分离UI层与业务层的一种开发模式被应用了很多年。在我们选择一种开发模式时,首先需要了解一下这种模式的利弊:

无论MVC或是MVP模式都不可避免地存如下弊端,这就导致了这两种开发模式也许并不是很小型应用。
> 额外的代码复杂度和学习成本

但比起他们的优点,这点弊端基本可以忽略了:
>
降低耦合度
> 模块职责划分明显
>
利于测试驱动开发
> 代码复用
>
隐藏数据
> 代码灵活性

对于MVP与MVC这两种模式,它们之间也有很大的差异。以下是这两种模式之间最关键的差异:
MVP模式:
>
View不直接与Model交互,而是通过与Presenter交互来与Model间接交互
> Presenter与View的交互是通过接口来进行的,更有利于添加单元测试
>
通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑

MVC模式:
> View可以与Model直接交互
>
Controller是基于行为的,并且可以被多个View共享
>* 可以负责决定显示哪个View
# MVVM
这里写图片描述
这里写图片描述
# Data-Binding
## 前言
  • 第三方的数据绑定框架随时有停止更新的风险,官方的则相对更稳定一些
  • 大量的findViewById,增加代码的耦合性
  • 虽然可以通过注解框架抛弃大量的findViewById,但是注解注定要拖慢我们代码的速度,Data Binding则不会,官网文档说还会提高解析XML的速度

这里不赘述了,下面几篇文章都讲的很详细!

精通 Android Data Binding
Android官方数据绑定框架DataBinding(一)
Android官方数据绑定框架DataBinding(二)
官方Data Binding Library

参考链接:

1、https://www.zhihu.com/question/21406685
2、http://liuling123.com/2015/12/mvp-pattern-android.html
3、http://www.2cto.com/kf/201506/405766.html
4、http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0313/2599.html
5、http://blog.csdn.net/qibin0506/article/details/47393725
6、http://zjutkz.net/2016/04/13/%E9%80%89%E6%8B%A9%E6%81%90%E6%83%A7%E7%97%87%E7%9A%84%E7%A6%8F%E9%9F%B3%EF%BC%81%E6%95%99%E4%BD%A0%E8%AE%A4%E6%B8%85MVC%EF%BC%8CMVP%E5%92%8CMVVM/#plg_nld=1&plg_auth=1&plg_nld=1&plg_dev=1&plg_uin=1&plg_usr=1&plg_vkey=1&plg_nld=1&more?hmsr=toutiao.io&utm_source=toutiao.io&plg_uin=1&plg_auth=1&utm_medium=toutiao.io&plg_dev=1&plg_nld=1&plg_usr=1&plg_vkey=1
7、http://blog.csdn.net/wusuopubupt/article/details/8817826
8、https://github.com/LyndonChin/MasteringAndroidDataBinding\
9、https://github.com/googlesamples/android-architecture
10、http://www.jianshu.com/p/569ab68da482
11、http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0425/4178.html
12、http://blog.csdn.net/vector_yi/article/details/24719873

SuS wechat
欢迎您扫一扫上面的微信公众号,订阅我的最新信息!
坚持原创技术分享,您的支持将鼓励我继续创作!