1.MVP简介:
相信大家对MVC设计模式早就有所了解,这种设计模式运用很广。在实际的安卓项目开发中,MVP模式当然是开发者的最爱,因为MVP将前后台完全分离,大大降低了Model和View的耦合。当然与Java的Spring MVC设计模式有点相似,但是还是有差异的。在 Android中很重要的一点就是对UI的操作基本上需要异步进行也就是在MainThread(主线程)中才能操作UI所以对View与Model的切断分离是合理的。此外Presenter与View、Model的交互使用接口定义交互操作可以进一步达到松耦合也可以通过接口更加方便地进行单元测试。所以也就有了这张图片(MVP和MVC的对比)。
Obviously,MVP中View和Model层是完全没有交互的,MVC中Model和View不仅可以通过Controller进行交互,他们也可以直接交互。(代码具体体会)。
2.MVP模型简单实例:
注:这里的Demo以一个简单的登录功能为例。
(1)View层
View层简单来说就是用户可见的活动,是什么活动呢,这里以登录界面为例,不光光是你看到的Button登录按钮,两个输入框(用户名,密码)。View层可以把你输入是数据取出然后调用Presenter层login(params)方法。(这里后面细说)。这里你要知道的是View层就是给Presenter层提供数据就OK。
这是view的接口:
package com.example.logintest.view;
/**
* Created By SunJin 2017/12/25
*/
public interface LoginUser {
String getName();
String getPassWord();
}
这是View的实现:
package com.example.logintest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.example.logintest.Medol.iModel.HttpCallbackListener;
import com.example.logintest.presenter.LoginPresenter;
import com.example.logintest.view.LoginUser;
/**
* Created By SunJin 2017/12/25
*/
public class MainActivity extends Activity implements LoginUser {
private Button login;
private EditText name;
private EditText passWord;
private LoginPresenter loginPresenter;
private TextView loginMessage;
//UI操作要在主线程中进行;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if( "Login success !".equals(msg.obj.toString())) {
Intent intent = new Intent(MainActivity.this, QQ.class);
Bundle bundle = new Bundle();
bundle.putString("name", name.getText().toString());
bundle.putString("pass", passWord.getText().toString());
intent.putExtras(bundle);
startActivity(intent);
} else {
loginMessage.setText("用户名:" + name.getText().toString() + " " +
"密码:" + passWord.getText().toString() + " " +
"提示:" + msg.obj.toString());
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initV();
}
private void initV() {
passWord = findViewById(R.id.passWord);
name = findViewById(R.id.name);
login = findViewById(R.id.login);
loginMessage = findViewById(R.id.loginMessage);
login.setOnClickListener(new loginListener());
loginPresenter = new LoginPresenter(this);
}
@Override
public String getName() {
return name.getText().toString();
}
@Override
public String getPassWord() {
return passWord.getText().toString();
}
private class loginListener implements View.OnClickListener {
@Override
public void onClick(View view) {
// Toast.makeText(MainActivity.this,"LoginTest",Toast.LENGTH_SHORT).show();
loginPresenter.login(new HttpCallbackListener() {
@Override
public void onFinish(String response) {
Message message = new Message();
message.obj = response;
mHandler.sendMessage(message);
}
@Override
public void onError(Exception e) {
Message message = new Message();
message.obj = e.toString();
mHandler.sendMessage(message);
}
});
}
}
}
看不懂View的实现没关系,因为后面要介绍Presenter。你现在要知道的是在View层中定义了Presenter。而Presenter层中有参构造方法的参数是View。
(2)Model层:
Model层是登录验证,连接后台的。那你就会问怎么连接后台的,怎么验证数据呢?别急,慢慢来。我这里写的Demo用的是封装好了的OkHttp3,验证是重新开线程访问后台(因为是个耗时操作)。刚刚上面说的Presenter调用的login()方法其实就是Presenter调用Model层的写好的实现方法。Model层的接口层是HttpCallbackListener接口,里面有两个回调函数,onFinish 和 onError()。具体实现在LoinModel层中。下面说login方法里面的三个参数,第一个是用户名,第二个是密码,第三当然是这个listener。在这里post请求返回得到的response后回调onFinish(假设没有异常)方法。这个时候在View层定义的Handler起作用了,因为登录成功或者失败要进行UI更新,所以这里也可以完全证明了V层和M层完全是分离的,需要P层传输。下面是Model层的接口和实现:
package com.example.logintest.Medol.iModel;
/**
* Created by SunJin on 2017/12/15.
*/
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}
package com.example.logintest.Medol;
import android.util.Log;
import com.example.logintest.Medol.iModel.HttpCallbackListener;
import org.json.JSONObject;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by Sunjin on 2017/12/25
*/
public class LoginModel {
private String responseDataJson;
private String URL = "http://222.198.38.53:3000/api/users";
public void login(String loginUserName, String loginUserPassWord,
final HttpCallbackListener listener) {
final String loginUser = loginUserName;
final String loginPass = loginUserPassWord;
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("loginUser", loginUser)
.add("loginPass",loginPass)
.build();
Request request = new Request.Builder()
.url(URL)
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
responseDataJson = response.body().string();
//成功则 回调onFinish
if (listener != null){
listener.onFinish( parseJSONWithJSONObject(responseDataJson));
}
}catch (Exception e) {
e.printStackTrace();
//出现异常则 回调onError
if (listener != null){
listener.onError(e);
}
}
}
}).start();
}
private String parseJSONWithJSONObject(String jsonData) {
String loginMark = "";
try {
Log.e("TAG",jsonData);
JSONObject jsonDataObject = new JSONObject(jsonData);
loginMark = jsonDataObject.getString("loginMark");
}catch (Exception e) {
e.printStackTrace();
}
return loginMark;
}
}
(3)P层:
P层其实也没啥好说的了,他的成员变量肯定是V和M。然后在构造方法的里面初始化其。直接上代码。
package com.example.logintest.presenter;
import com.example.logintest.Medol.iModel.HttpCallbackListener;
import com.example.logintest.Medol.LoginModel;
import com.example.logintest.view.LoginUser;
/**
* Created by Sunjin on 2017/12/15.
*/
public class LoginPresenter {
private LoginUser loginUser;
private LoginModel loginMedol;
public LoginPresenter(LoginUser loginUser) {
this.loginUser = loginUser;
this.loginMedol = new LoginModel();
}
public void login(HttpCallbackListener listener) {
loginMedol.login(loginUser.getName(), loginUser.getPassWord(),listener);
}
}
3.小结
本人写此博客纯属抱着一种学习的态度。我也是初学者,希望大家指出错误,共同进步。
另外,详细代码请参考git上开源项目连接:MVPDemo开源