android MVP模式 个人思考

来源:互联网 发布:java初级工程师面试 编辑:程序博客网 时间:2024/05/18 02:21

之前去参加过一个面试,技术面的时候问到我现在开发都用什么架构,我一下懵逼了。这么小的项目还考虑毛框架啊。
这几天又开始新项目框架搭建的时候,时间没那么紧,开始打算考虑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下的工程,只有全部结构代码,不保证完全运行

0 0