之前去参加过一个面试,技术面的时候问到我现在开发都用什么架构,我一下懵逼了。这么小的项目还考虑毛框架啊。
这几天又开始新项目框架搭建的时候,时间没那么紧,开始打算考虑android项目的框架问题,看有没有借鉴的地方。对MVP,MVVM进行了大量资料查询,说实话,可能是本人思维有了定式,能看懂MVP的结构,但是对MVP模式依然很难以完全适应。
以下内容全是个人见解,有可能是学习不够,有可能是理解本身不够,未能理解到MVP精髓,欢迎留言指正。
进入正题,关于MVP模式的讲解以及代码结构,网上一搜一大堆,但是我个人感觉,网上除了直接复制粘贴完全一样的,不一样的实现内容之间的代码结构都略有不同。我只拿其中一个实现login的说一说个人理解。
从网上的资料来看,MVP模式作用包括:
1.拆分了Activity文件,大幅度减少Activity中的代码量,方便维护阅读。
2.独立出的view层和model层之间通过presenter进行管理,减少两层之间的耦合,某一层做改动不影响另一层。
3.分层过后方便测试。
4.提高代码复用率。
以上是我个人理解到的MVP模式的好处,但是研究了几个MVP模式的demo后发现,感觉MVP框架的思想有点强行为了分层而分层的感觉,难以一下子适应,而且关键在于MVP中将activity分层到view层,但是activity涉及到的生命周期、广播服务、handler等,在我看来依然属于控制层的范畴,在目前看到demo中,activity不可避免的出现了控制数据流向的代码。
所以基于MVP,我个人调整了下代码结构和逻辑,按照我的理解对项目进行了分层设计。
结构依然分成3层结构,view、controller、model,但是对MVP的实现方式做了调整。
view层不继承activity,通过构造函数或者init方式拿到activity和controller抽象接口,view中仅实现获取界面内容、展示内容的部分。
controller层继承activity,自然也继承了activity的生命周期,以及服务广播等信息来源。controller通过在oncreate中调用view层的init方法,实现界面的初始加载等,其后如果有信息需要展示,通过view实现的方法来进行展示。
model层与MVP的没有区别。都是定义实体类,实现对应的数据存取操作等。
以下是我的代码分层(eclipse下,内存太小,用不上studio):
MainViews:
public class MainViews extends BaseViews<MainControllerInterface> {
private EditText edt_username, edt_password;
private OnClickListener clickListener;
@Override
public void init(final Activity a, final MainControllerInterface c) {
a.setContentView(R.layout.main);
edt_username = (EditText) a.findViewById(R.id.edt_username);
edt_password = (EditText) a.findViewById(R.id.edt_password);
clickListener = new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_login:
User u = new User(getUsername(), getPassword());
if (TextUtils.isEmpty(u.getUsername()) || TextUtils.isEmpty(u.getPassword())) {
return;
}
c.onLoginBtnClicked(u);
break;
default:
break;
}
}
};
a.findViewById(R.id.btn_login).setOnClickListener(clickListener);
}
public boolean onCreateOptionsMenu(Activity a, Menu menu) {
a.getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public boolean onOptionsItemSelected(MainController c, MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_settings:
c.onMenuSettingSelected();
break;
default:
break;
}
return false;
}
protected String getUsername() {
// TODO 验证合法性,弹出提示等
return edt_username.getText().toString();
}
protected String getPassword() {
// TODO 验证合法性,弹出提示等
return edt_password.getText().toString();
}
public void setLoginSucess(Object beanNeedForShow) {
// TODO
}
public void setLoginFailed(Object beanNeedForShow) {
// TODO
}
@Override
public void destory() {
}
MainController:
public class MainController extends Activity implements MainControllerInterface {
private MainViews views;
private UserModel userModel;
// private TestService bleService;处理service
// private ServiceConnection conn;
// private Handler handler;//处理handler内容
// private BroadcastReceiver receiver;//处理广播内容
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (userModel == null) {
userModel = new UserModel(getApplicationContext());
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return views.onCreateOptionsMenu(this, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return views.onOptionsItemSelected(this, item);
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
views.destory();
super.onDestroy();
}
public void onMenuSettingSelected() {
// TODO
}
@Override
public void onLoginBtnClicked(User u) {
// TODO
userModel.login(u, new CallBack() {
@Override
public void onSuccess(User u) {
views.setLoginSucess(new Object());
}
@Override
public void onFailed(User u, Exception e) {
views.setLoginFailed(new Object());
}
});
}
public void setViews(MainViews views) {
this.views = views;
}
}
UserModel:
public class UserModel {
private Context ctx;
public UserModel(Context ctx) {
this.ctx = ctx;
}
public void login(User u, CallBack c) {
// 访问本地数据,网络数据等
// 可以同步传入handler,callback等,以便接收异步数据
// 此处demo直接使用暂定的callback
}
public interface CallBack {
public void onSuccess(User u);
public void onFailed(User u, Exception e);
}
}
demo代码中,我做了login的3层贯通,但是有些具体实现细节没有完全实现。
BaseViews和Controller接口,是我在用这个架构套用在之前的一个小项目上提炼出来的,不是必须。
之前我用过这个分层结构来进行过测试,但是由于我个人以前从未系统的进行android单元测试等,只能简单的用Robolectric进行了一下简单试验。
Model层的测试比较简单。
Controller层是用的笨办法,通过set方法注入了一个空实现的Views和一个直接返回特定结果的Model实现类进行的。
View层因为按照这个分层方式,只会有简单的页面显示功能,个人感觉如果需要,可以直接通过实现一个返回特定结果的Controller来进行点点点测试。
这个是我个人调整后的代码结构,不会更改现有的开发思路,所有的数据都汇集到controller中,再由controller来确定数据流向。分层结构后逻辑简单(有可能因为demo逻辑本来就弱),所有逻辑都在controller中实现,层与层之间也能做到互不影响。
以上是我个人对android的MVP模式的理解和个性化调整,如果有感兴趣的朋友,欢迎拍砖指正交流。
附上我demo的代码:eclipse下的工程,只有全部结构代码,不保证完全运行