Android MVP 架构示例

来源:互联网 发布:日本黑社会电影知乎 编辑:程序博客网 时间:2024/04/28 20:02

首先说明:这篇博客参考资料 鸿神的MVP博客 内容上有着很大的相似性。

如果是比较初级的读者,只是开始接触MVP,我建议可以看一下我的另外两个博客,个人认为对理解MVP有帮助而写的比较不美观的博客

一、 MVP前奏(一)接口

二、MVP前奏(二)MVCAndroid的小短腿

我觉得编程这个东西,开始不一定非要深入,只要先上手使用就好了,用着用着,认识会随着熟练度增长,有了一定的熟练度后再去深入研究问题,也能事半功倍了。


做个说明:ui包的activity几乎都继承了view中定义的接口,ui是属于V的;

biz包定义了接口和实际操作,OnloginListener是登录的回调接口,属于P层;

M层只有一个model

至于base包,请忽略。


开始正文:

这个demo使用MVP实现了两点小功能

1.realm存一个用户信息;

2.Rxjava模拟登录。

最简单的M开始,只定义了用户模型User,因为要使用realm存储,所以User继承了RealmObject

<span style="font-size:18px;">package com.hcsw.newtecset.model;import io.realm.RealmObject;/** * Created by Administrator on 2016/3/9. */public class User extends RealmObject{    private String userName;    private String password;    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }}</span>

我的一篇关于Realm的简单博客


接下来是V层

由IRealmView定义RealmActivity需要实现的功能,将来IRealmView会作为RealmActivity的代表参与操作:

<span style="font-size:18px;">package com.hcsw.newtecset.view;/** * Created by Administrator on 2016/3/10. */public interface IRealmView {    String getUserName();//获取输入的用户名    String getPassword();//获取输入的密码    void toLoginActivity();//添加成功后的操作    void showTip(String tip);//关闭Realm}</span>

关于BaseActivity的代码稍后贴出。

<span style="font-size:18px;">package com.hcsw.newtecset.ui;import android.content.Intent;import android.view.View;import android.widget.EditText;import android.widget.LinearLayout;import android.widget.Toast;import com.hcsw.newtecset.R;import com.hcsw.newtecset.base.BaseActivity;import com.hcsw.newtecset.presenter.RealmPresenter;import com.hcsw.newtecset.view.IRealmView;public class RealmActivity extends BaseActivity implements IRealmView {    private EditText edtName,edtPwd;    private RealmPresenter presenter;    @Override    public int getContentViewId() {        return R.layout.activity_main;    }    @Override    public int getTitleBarId() {        return -1;    }    @Override    protected String getActivityTitleTxt() {        return "设置用户信息";    }    @Override    protected void initIntent() {    }    @Override    public void initComponents() {        setTitleBarAction();        findViewById(R.id.title_bar_left_area).setVisibility(View.INVISIBLE);        presenter = new RealmPresenter(this);        edtName = (EditText) findViewById(R.id.edt_username);        edtPwd = (EditText) findViewById(R.id.edt_password);        findViewById(R.id.btn_save).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                presenter.insertUser();            }        });    }    @Override    public void loadData() {    }    @Override    public boolean isResumeLoad() {        return false;    }    @Override    protected void onDestroy() {        super.onDestroy();        presenter.closeRealm();    }    @Override    public String getUserName() {        return edtName.getText().toString();    }    @Override    public String getPassword() {        return edtPwd.getText().toString();    }    @Override    public void toLoginActivity() {        startActivity(new Intent(this,LoginActivity.class));    }    @Override    public void showTip(String tip) {        Toast.makeText(this,tip,Toast.LENGTH_LONG).show();    }}</span>
由ILoginView定义LoginActivity需要实现的功能,将来ILoginView会作为LoginActivity的代表参与操作:
package com.hcsw.newtecset.view;/** * Created by Administrator on 2016/3/9. */public interface IUserLoginView {    String getUserName();//获取账号    String getPassword();//获取密码    void cleanUserName();//清除账号    void cleanPassword();//清除密码,两个可以合并为一个清楚方法    void showLoading();//显示表示“登录中”的progressbar    void hideLoading();//隐藏表示“登录中”的progressbar    void onLoginSuccess();//处理登录成功的方法    void onLoginFailed();//处理登录失败的方法}

package com.hcsw.newtecset.ui;import android.app.ProgressDialog;import android.content.Intent;import android.view.View;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.Toast;import com.hcsw.newtecset.R;import com.hcsw.newtecset.base.BaseActivity;import com.hcsw.newtecset.presenter.LoginPresenter;import com.hcsw.newtecset.view.IUserLoginView;/** * Created by Administrator on 2016/3/9. */public class LoginActivity extends BaseActivity implements IUserLoginView{    ProgressBar pLoading;    LoginPresenter presenter;    private EditText edtName,edtPwd;    @Override    public int getContentViewId() {        return R.layout.activity_login;    }    @Override    public int getTitleBarId() {        return -1;    }    @Override    protected String getActivityTitleTxt() {        return "登录";    }    @Override    protected void initIntent() {    }    @Override    public void initComponents() {        presenter = new LoginPresenter(this);        setTitleBarAction();        findViewById(R.id.title_bar_left_area).setVisibility(View.INVISIBLE);        edtName = (EditText) findViewById(R.id.edt_username);        edtPwd = (EditText) findViewById(R.id.edt_password);        pLoading = (ProgressBar) findViewById(R.id.pb_loading);        findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                presenter.login();            }        });        findViewById(R.id.btn_clean).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                presenter.clear();            }        });    }    @Override    public void loadData() {    }    @Override    public boolean isResumeLoad() {        return false;    }    @Override    public String getUserName() {        return edtName.getText().toString();    }    @Override    public String getPassword() {        return edtPwd.getText().toString();    }    @Override    public void cleanUserName() {        edtName.setText("");    }    @Override    public void cleanPassword() {        edtPwd.setText("");    }    @Override    public void showLoading() {        pLoading.setVisibility(View.VISIBLE);    }    @Override    public void hideLoading() {        pLoading.setVisibility(View.GONE);    }    @Override    public void onLoginSuccess() {        Toast.makeText(this,"Success",Toast.LENGTH_LONG).show();        startActivity(new Intent(this,SecondActivity.class));    }    @Override    public void onLoginFailed() {        Toast.makeText(this,"failed",Toast.LENGTH_LONG).show();    }}



再接下来是P

Realm和登录分别创建接口IRealmBizIUserBiz,定义需要实现的内容方法。

IRealmBiz定义了增、删、改、查和关闭数据库五个方法,由RealmBiz继承实现:

<span style="font-size:18px;">package com.hcsw.newtecset.biz;import com.hcsw.newtecset.model.User;/** * Created by Administrator on 2016/3/10. */public interface IRealmBiz {    void insertRealm(String name,String pwd);    User selectRealm();    void deleteRealm(User user);    void uploadRealm(User user);    void closeRealm();}</span>
<span style="font-size:18px;">package com.hcsw.newtecset.biz;import com.hcsw.newtecset.model.User;import io.realm.Realm;/** * Created by Administrator on 2016/3/10. */public class RealmBiz implements IRealmBiz{    private Realm realm;    public RealmBiz(){        realm = Realm.getDefaultInstance();    }    @Override    public void insertRealm(String name,String pwd) {        realm.beginTransaction();        User user = realm.createObject(User.class);        user.setUserName(name);        user.setPassword(pwd);        realm.commitTransaction();    }    @Override    public User selectRealm() {        realm.beginTransaction();        User user = realm.where(User.class).findFirst();        realm.commitTransaction();        return user;    }    @Override    public void deleteRealm(User user) {        realm.beginTransaction();        realm.commitTransaction();    }    @Override    public void uploadRealm(User user) {        realm.beginTransaction();        realm.commitTransaction();    }    @Override    public void closeRealm() {        realm.beginTransaction();        realm.where(User.class).findAll().clear();        realm.commitTransaction();        realm.close();    }}</span>

关于realm = Realm.getDefaultInstance()这句,请参照后面贴出的MyApplication代码;

IUserBiz只定义了一个login方法,并设置了三个参数,由UserBiz继承实现,OnloginListener是作为登录结果监听的接口,只有成功和失败两个方法:

<span style="font-size:18px;">package com.hcsw.newtecset.biz;/** * Created by Administrator on 2016/3/9. */public interface IUserBiz {    void login(String name,String password,OnloginListener listener);}</span>

这里用到了一些Rxjava的语法。

<span style="font-size:18px;">package com.hcsw.newtecset.biz;import com.hcsw.newtecset.model.User;import java.util.concurrent.TimeUnit;import io.realm.Realm;import rx.Observable;import rx.Observable.OnSubscribe;import rx.Observer;import rx.Subscriber;import rx.android.schedulers.AndroidSchedulers;import rx.functions.Action1;import rx.functions.Func1;import rx.schedulers.Schedulers;/** * Created by Administrator on 2016/3/9. */public class UserBiz implements IUserBiz{    @Override    public void login(final String name, final String password, final OnloginListener listener) {        Observable                .create(new OnSubscribe<Boolean>() {                    @Override                    public void call(Subscriber<? super Boolean> subscriber) {                        Realm realm = Realm.getDefaultInstance();                        User user = realm.where(User.class).findFirst();                        String u = user.getUserName();                        String p =user.getPassword();                        boolean b = u.equals(name)&&p.equals(password);                        subscriber.onNext(b);                    }                })                .subscribeOn(Schedulers.io())                .delay(2, TimeUnit.SECONDS)                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new Action1<Boolean>() {                    @Override                    public void call(Boolean aBoolean) {                        if(aBoolean){                            User user = new User();                            user.setUserName(name);                            user.setPassword(password);                            listener.loginSuccess(user);                        }else{                            listener.loginFailed();                        }                    }                });    }}</span>
<span style="font-size:18px;">package com.hcsw.newtecset.biz;import com.hcsw.newtecset.model.User;/** * Created by Administrator on 2016/3/9. */public interface OnloginListener {    void loginSuccess(User user);    void loginFailed();}</span>

代码关联处理关系整合的关键类,接下来的类就如同是交通枢纽,将整个结构联系起来:

<span style="font-size:18px;">package com.hcsw.newtecset.presenter;import com.hcsw.newtecset.biz.RealmBiz;import com.hcsw.newtecset.view.IRealmView;/** * Created by Administrator on 2016/3/10. */public class RealmPresenter {    private RealmBiz realmBiz;    //代理处理RealmActivity中的方法    private IRealmView iRealmActivity;    public RealmPresenter(IRealmView iActivity){        realmBiz = new RealmBiz();        iRealmActivity = iActivity;    }    public void insertUser(){        //参数通过iRealmActivity获取RealmActivity中的实际值        realmBiz.insertRealm(iRealmActivity.getUserName(),iRealmActivity.getPassword());        //结果返回RealmActivity处理        iRealmActivity.showTip("插入数据完成");        iRealmActivity.toLoginActivity();    }    //关闭数据库    public void closeRealm(){        realmBiz.closeRealm();    }}</span>

<span style="font-size:18px;">package com.hcsw.newtecset.presenter;import com.hcsw.newtecset.biz.OnloginListener;import com.hcsw.newtecset.biz.UserBiz;import com.hcsw.newtecset.model.User;import com.hcsw.newtecset.view.IUserLoginView;import java.util.concurrent.TimeUnit;import rx.Observable;import rx.Subscriber;import rx.android.schedulers.AndroidSchedulers;import rx.functions.Action1;/** * Created by Administrator on 2016/3/9. */public class LoginPresenter {    UserBiz userBiz;    //LoginActivity的代表    IUserLoginView userLoginView;    public LoginPresenter(IUserLoginView loginView){        this.userLoginView = loginView;        userBiz = new UserBiz();    }    public void login(){        userLoginView.showLoading();                userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnloginListener() {            @Override            public void loginSuccess(final User user) {                //Rxjava的语法,在收到成功后执行                Observable                        .create(new Observable.OnSubscribe<User>() {                            @Override                            public void call(Subscriber<? super User> subscriber) {                                subscriber.onNext(user);                            }                        })                        .observeOn(AndroidSchedulers.mainThread())                        .subscribe(new Action1<User>() {                            @Override                            public void call(User user) {                                userLoginView.hideLoading();                                userLoginView.onLoginSuccess();                            }                        });            }            @Override            public void loginFailed() {                Observable                        .create(new Observable.OnSubscribe<String>() {                    @Override                    public void call(Subscriber<? super String> subscriber) {                        subscriber.onNext("");                    }                })                        .observeOn(AndroidSchedulers.mainThread())                        .subscribe(new Action1<String>() {                            @Override                            public void call(String user) {                                userLoginView.hideLoading();                                userLoginView.onLoginFailed();                            }                        });            }        });    }    public void clear(){        userLoginView.cleanUserName();        userLoginView.cleanPassword();    }}</span>

上一张MVC和MVP的区别图(图片原文):


我的手工图:


个人总结:M层没有变化;V层增加了接口,在activity继承的时候,通过接口的特性,使接口可以代理的操作Activity中的实际内容交给P层的Presenter类处理;而P层预定好处理业务,在Presenter类中将业务和数据结合,然后将结构返回V层,实现V和M的分离和不再高耦合。

个人觉得这里最重要的就是通过接口的实现的各种调用。理解接口很重要
demo下载地址

1 0
原创粉丝点击