入门级 MVP

来源:互联网 发布:韩顺平php从入门到精通 编辑:程序博客网 时间:2024/05/17 05:14

前段时间在腾讯课堂看了一个关于 MVP 模式讲解的直播,整体看下来感觉还是相当适用于一直对于 MVP 处于理论了解的新手。
这里对于理论知识我就不多说废话了,相信大多数朋友都有所了解。
那么我们就直接开始进行贴代码。最后我会附加一个讲解 MVP 的视频地址(不会的童鞋推荐去看一下)。

MVP中的 V

首先,我们先来新建一个 V 的接口:

public interface IBaseMvpView {}

这里是作为所有V 的 父类,可以根据自己需要添加一些方法,这里我是没添加什么共有的方法。

MVP中的 P

创建 Presenter 类:

public class BaseMvpPresenter<V extends IBaseMvpView> {    private V view;    public V getView() {        return view;    }    //用来绑定 View层    public void attachView(V view) {        this.view = view;    }    // 解除绑定View    public void detachView() {        this.view = null;    }}

因为要绑定 MVP中的 V 所以用了一个泛型。这里我省略了 IBaseMvpPresenter 接口,直接进行添加绑定方法。不想省略的话,可以这么写:

public interface IBasePresenter<V extends IBaseMvpView> {    V getView();    void attachView(V view);    void detachView();}
public class BaseMvpPresenter<V extends IBaseMvpView> implements IBasePresenter<V> {    private V view;    @Override    public V getView() {        return view;    }    @Override    public void attachView(V view) {        this.view = view;    }    @Override    public void detachView() {        this.view = null;    }}

以上是创建了 View ,Presenter 的基类,至于 M 层我们直接根据业务来进行创建,可以不需要基类。

LoginDemo

下面写一个登录示例来看一下怎么去结合使用

  • 创建 LoginView 接口(用于处理登录结果,操作界面)
public interface LoginView3 extends IBaseMvpView {    // 返回登录结果    void onResult(String result);}
  • 创建 LoginModel (用于处理登录界面的所有逻辑处理)
public class LoginModel3 {    // 进行登录请求    public void login(String userName, String passWord, IHttpResultListener listener) {        Http.http_login(userName, passWord, listener);    }     /**     * 保存登录用户数据     */    public void saveUserData(){        //...    }    ...}
  • 创建 LoginPresenter (协调 View 和 Model 之间的调度)
public class LoginPresenter3 extends BaseMvpPresenter<LoginView3> {    private LoginModel3 loginModel;    public LoginPresenter3() {        loginModel = new LoginModel3();    }    /**     * 登录     *     * @param userName     * @param passWord     */    public void login(String userName, String passWord) {        loginModel.login(userName, passWord, new IHttpResultListener() {            @Override            public void onResult(String t) {                // 其他的数据操作。                loginModel.saveUserData();                if (getView() != null) {                    // 最终返回界面,进行 UI 操作。                    getView().onResult(t);                }            }        });    }}
  • 完成整个流程
    为了统一处理,我直接在 BaseActivity 中进行了 View 的绑定 和解绑操作。
public abstract class BaseActivity<V extends IBaseMvpView, P extends BaseMvpPresenter<V>> extends FragmentActivity {    private P presenter;    public abstract P bindPresenter();    public P getPresenter() {        return presenter;    }    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (presenter == null) {            presenter = bindPresenter();            if (presenter != null && this instanceof IBaseMvpView) {                presenter.attachView((V) this);            }        }    }    @Override    protected void onDestroy() {        super.onDestroy();        if (presenter != null) {            presenter.detachView();        }    }}

下面才是我们的 LoginActivity

public class LoginActivity extends BaseActivity<LoginView3, LoginPresenter3> implements LoginView3 {    @Override    public LoginPresenter3 bindPresenter() {        return new LoginPresenter3();    }    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_login);    }    public void clickLogin(View view) {        getPresenter().login("发强", "123456");    }    @Override    public void onResult(final String s) {        Toast.makeText(LoginActivity.this, s, Toast.LENGTH_SHORT).show();        Log.i("lfq", "login Result: " + s);    }}

界面要注意实现相关的 View 接口

他们之间的流程是 :
在 Activity 中绑定 Presenter 。当点击登录按钮时,通过 Presenter 去调用 LoginModel 中相应的登录操作。当 LoginModel 的登录操作返回结果时,再通过 Presenter 去调用 LoginView 中的相关操作界面方法。

一个入门级的 MVP 模式差不多就这些了。想要更好的使用,可以参考一下 Google官方的 MVP demo . 这里附上一篇解析的文章 Android官方MVP架构示例项目解析 .

LoginModel 中的登录实现,我这边是用了最原始的方法 HttpURLConnection ,然后本地新建了一个 Servlet服务端去简单的操作了一下,你可以用自己的实现方式,比如 retrofit 请求。我这是只是为了温故一下相关知识点。
代码如下:

public class Http {    public static void http_login(String userName, String password, IHttpResultListener listener) {        Map<String, Object> map = new HashMap<>();        map.put("userName", userName);        map.put("passWord", password);        HttpUtil.post("login", map, listener);    }}
public class HttpUtil {    static final String HTTP = "http://192.168.2.1:8080/";    private static Handler handler = new Handler();    public static void post(final String url, final Map<String, Object> params, final IHttpResultListener listener) {        new Thread(new Runnable() {            @Override            public void run() {                String result = "";                HttpURLConnection conn = null;                OutputStream out = null;                BufferedReader reader = null;                try {                    StringBuilder paramsStr = new StringBuilder();                    if (params != null && params.size() > 0) {                        for (Map.Entry<String, Object> entry : params.entrySet()) {                            paramsStr.append(entry.getKey()).append("=").append(entry.getValue().toString()).append("&");                        }                        paramsStr.deleteCharAt(paramsStr.length() - 1);                    }                    URL u = new URL(HTTP + url);                    conn = (HttpURLConnection) u.openConnection();                    // 设置连接参数                    conn.setDoOutput(true);                    conn.setDoInput(true);                    conn.setRequestMethod("POST");// 设置以POST方式                    conn.setUseCaches(false); // Post请求不使用缓存                    conn.setInstanceFollowRedirects(true);                    conn.setRequestProperty("Content-Type",                            "application/x-www-form-urlencoded");                    conn.setRequestProperty("Charset", "UTF-8");                    conn.setConnectTimeout(10000);                    conn.setReadTimeout(10000);                    // 上传的参数                    Log.i("lfq", paramsStr.toString());                    out = conn.getOutputStream();                    out.write(paramsStr.toString().getBytes());                    out.flush();                    out.close();                    reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));                    StringBuffer strBuf = new StringBuffer();                    String str = null;                    while ((str = reader.readLine()) != null) {                        strBuf.append(str);                    }                    result = strBuf.toString();                    Log.i("lfq", strBuf.toString());                } catch (Exception e) {                    e.printStackTrace();                    result = e.toString();                } finally {                    try {                        if (out != null) {                            out.close();                        }                        if (reader != null) {                            reader.close();                        }                        if (conn != null) {                            conn.disconnect();                        }                    } catch (IOException e) {                        e.printStackTrace();                    }                }                if (listener != null) {                    final String res = result;                    handler.post(new Runnable() {                        @Override                        public void run() {                            listener.onResult(res);                        }                    });                }            }        }).start();    }}

大致的代码就这些了。有兴趣的可以去试试。

最后附上一个别人录制的 MVP 相关讲解视频,网盘地址:https://pan.baidu.com/s/1pL9cykb ,提取码:j7ab