前段时间在腾讯课堂看了一个关于 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