初学MVP

来源:互联网 发布:同性电影推荐知乎 编辑:程序博客网 时间:2024/03/28 23:31

一直听群里的人说MVP模式去开发app 自己也搜藏了几篇文章 但一直没事件去学习,正好这两天有空闲的时间就尝试写个demo出来看看。概念信的东西我就不写了 网上的文章对于MVP的概念大致都是一样的。对于新东西 我一般是通过先写出个demo 以后在运用的过程再去学习此东西里面的详细内容。
建立MVP 项目 一般需要 建立 view(界面逻辑),model(业务逻辑),presenter(调度)这几个包名。当然项目离不开 bean(实体数据) 基本上这几个包名就能组成 一个基本的MVP框架了 其它的包名根据自己的需要建立

此次demo我采用的rxjava和retrofit来完成线程调度和网络请求 既然是新的不错的东西 为什么不用呢。
最后我的工程结构为
这里写图片描述
首先从 看看api包里的LoginApi 里面是retrofit的网络请求 非常简单 强烈建议大家使用retrofit 我是看这篇文章学习的
https://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=2653577186&idx=1&sn=1a5f6369faeb22b4b68ea39f25020d28&scene=1&srcid=0605oJ1NiiihvcW5jF8iy3n6&key=f5c31ae61525f82e38a1a943febc987278275256a5df936f1119c6514ebc78df82fc229de80607e2372e4c0f1451e4db&ascene=0&uin=Mjc3OTU3Nzk1&devicetype=iMac+MacBookPro10%2C1+OSX+OSX+10.10.5+build%2814F1808%29&version=11020201&pass_ticket=Yfzg8hN3fuLjjXoQDSG%2BBKWgRxryyVOFVwGFzsu7nB%2FgSZp9gdXJS%2FudxKZSNLan

public interface LoginApi {    @POST("testMvp.aspx")    @FormUrlEncoded    Observable<Response<User>> login(@Field("do") String action, @Field("user_info") String userInfo);}

base里面封装着基本所有界面和所有业务都需要的方法 这几个类基本不需要做任何修改只需要拷贝到下一个工程 当然你也可以根据需要在里面扩展你想要的方法 关于封装 我借鉴的是
https://github.com/183619962/MVPTest

public class BaseModel {    //retrofit请求数据的管理类    public RetrofitManager retrofitManager;    public BaseModel() {        //初始化retrofit        retrofitManager = RetrofitManager.builder();    }}
public class BasePresenter <T extends IBaseView,V> implements IBasePresenter, Observer<V> {    public IBaseView iView;    /**     * 构造方法     *     * @param view 具体业务的接口对象     */    public BasePresenter(T view) {        this.iView = view;    }    @Override    public void onResume() {    }    @Override    public void onDestroy() {    }    @Override    public void onCompleted() {        iView.hideProgress();    }    @Override    public void onError(Throwable e) {        iView.loadDataError(e);        iView.hideProgress();    }    @Override    public void onNext(V t) {        iView.loadDataSuccess(t);    }}
public interface IBasePresenter {    /**     * 开始<br>     * 用于做一些初始化的操作     */    void onResume();    /**     * 销毁<br>     * 用于做一些销毁、回收等类型的操作     */    void onDestroy();}
public interface IBaseView<T> {    /**     * 显示提示消息     *     * @param msg     */    void toast(String msg);    /**     * 显示进度     *     * @param progress     */    void showProgress(int progress);    /**     * 隐藏进度     */    void hideProgress();    /**     * 请求成功     * @param data     */    void loadDataSuccess(T data);    /**     * 请求错误     * @param throwable     */    void loadDataError(Throwable throwable);    /**     * 开始加载     */    void startLoading();}

好了 前面的基本工作都做完了 界面该实现真正的功能了
我实现的是登陆功能
我先实现登陆功能的逻辑 也就是先实现LoginModel
首先登陆之前需要初始化 登陆请求接口 然后才是传递参数实现登陆 基本上就这个两点 那么转换成代码就是

public class LoginModel extends BaseModel {    private Context context;    private LoginApi loginApi;    /**     * 初始化登陆请求接口     * @param context     */    public LoginModel(Context context) {        this.context = context;        loginApi = retrofitManager.getLoginApi();    }    /**     * 实现登陆     * @param userName     * @param pwd     * @param observer     */    public void login(String userName, String pwd, final Observer observer) {        String userInfo = "{\"name\":\"" + userName + "\"," +                "\"pwd\":\"" + pwd + "\"" +                "}";        loginApi.login("login",userInfo).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Response<User>>() {            @Override            public void onCompleted() {            }            @Override            public void onError(Throwable e) {                observer.onError(e);            }            @Override            public void onNext(final Response<User> jsonObjectResponse) {                /**                 * 延迟一下再返回结果 这样能看到 登陆的动画 可以不用延时直接返回                 */                 new Handler().postDelayed(new Runnable() {                    @Override                    public void run() {                        if (jsonObjectResponse.code() == 200) {                            observer.onNext(jsonObjectResponse.body());                            observer.onCompleted();                        } else {                            onError(new Throwable("网络错误"));                        }                    }                },3000);            }        });    }}

然后实现VIEW
写之前根据逻辑来分析需要哪些方法 登陆的话 需要 用户名和用户密码 这两个是必须的 接下来可以有 清除密码 清除用户名 等 不必须的方法可以用有可以没有 根据上面的分析可以写出以下代码

/*** 封装好登陆view方法 让activity(也就是view)去实现它*/public interface ILoginView extends IBaseView<User>{    /**     * 获取用户名     * @return     */    String getUserName();    /**     * 获取用户密码     * @return     */    String getPwd();    /**     * 清除用户名     */    void clearnUserName();    /**     * 清除用户密码     */    void clearnPwd();}

接下来就是presenter实现调度了
presenter 首先它需要从view(也就是activity)成拿到数据 然后再把数据交给model(也就是业务层去处理) model处理完业务逻辑 返回数据给 presenter 再有presenter 反馈给 view(activity) 根据这个思路 我们需要定义一个LoginModel 和一个IView

public class LoginPresenter extends BasePresenter<ILoginView,User> {    private LoginModel loginModel;    private Context context;    /**     * 构造方法     *     * @param view 具体业务的接口对象     */    public LoginPresenter(ILoginView view,Context context) {        super(view);        this.context = context;        loginModel = new LoginModel(context);    }    /**     * 登陆     * @param userName     * @param pwd     */    public void login(String userName,String pwd) {        onResume();        iView.startLoading();        iView.showProgress(0);        loginModel.login(userName,pwd,this);    }}

注意此处为什么没有定义IView 是因为BasePresenter里已经定义好了一个IBaseView(可以看看上面的 BasePresenter的定义)
子类继承父类的public IBaseView 自然就存在了 当LoginPresenter被初始化时就会初始化IView

最后一步
真正的view(activity)
初始化activity上的控件 控件有 Edittext userName; Edittext pwd; Button login;
view 和presenter进行交互 view把数据交给presenter
[ 然后presenter把数据交给model,model处理数据(登陆服务器 登陆成分返回数据给presenter presenter 反馈给activity 登陆失败model返回给presenter ,presenter反馈给activity) ] 中括号里的不走 由前面我们定义好的逻辑自动实现

public class LoginActivity extends BaseActivity implements ILoginView {    @BindView(R.id.editText)    EditText userName;    @BindView(R.id.editText2)    EditText pwd;    @BindView(R.id.button)    Button login;    @BindView(R.id.loginNotice)    RelativeLayout loginNotice;    private LoginPresenter loginPresenter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState,R.layout.activity_login);        loginPresenter = new LoginPresenter(this, this);    }    @Override    public String getUserName() {        return userName.getText().toString();    }    @Override    public String getPwd() {        return pwd.getText().toString();    }    @Override    public void clearnUserName() {    }    @Override    public void clearnPwd() {    }    @Override    public void toast(String msg) {    }    @Override    public void showProgress(int progress) {        loginNotice.setVisibility(View.VISIBLE);    }    @Override    public void hideProgress() {        loginNotice.setVisibility(View.GONE);    }    /**     * 请求成功     *     * @param data     */    @Override    public void loadDataSuccess(User data) {        if (data.isMessageStatus()) {            Toast.makeText(LoginActivity.this, "登陆成功!", Toast.LENGTH_SHORT).show();        } else {            Toast.makeText(LoginActivity.this, "登陆失败!" + data.getMessage(), Toast.LENGTH_SHORT).show();        }    }    /**     * 请求错误     *     * @param throwable     */    @Override    public void loadDataError(Throwable throwable) {        throwable.printStackTrace();        Toast.makeText(LoginActivity.this, "登陆失败!", Toast.LENGTH_SHORT).show();    }    /**     * 开始加载     */    @Override    public void startLoading() {        Log.e(TAG,"开始登陆");    }    @OnClick(R.id.button)    public void onClick() {        loginPresenter.login(getUserName(), getPwd());    }}

好了一个mvp的登陆功能就完成 实现更多的功能只需要 按照上面的步骤实现 model 实现IView 实现 presenter 再通过view(activity) 进行调度就行了
本文采用的是 butterknife 有更好的 dragger2 和databinding 深度解耦

此篇文章 我只是从我学习的角度写出来的 有写错的地方请给出意见 如果是大神请飘过

0 0