android MVP模式 个人思考

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值