下面这个图,就解释了MVP的数据流:
其中MVP,核心为Presenter,View与Model没有数据之间的交互。而MVC,核心为Controller,View与Model有数据之间的交互。
所以MVP最大的优点就是Model与View之间的完全解耦。
android 架构
https://github.com/googlesamples/android-architecture
todo-mvp 架构 github网站
https://github.com/googlesamples/android-architecture/tree/todo-mvp/
当你下载google官方的Demo后,建议你好好看看。
如果你一脸懵逼,可能你需要一些说明的资料:
Android官方MVP架构项目解析
http://www.android-doc.com/androiddocs/2017/0803/1218.html
这样参照对比的看,你才会看出来一点门道的。
这是我参考官方Demo,再结合Android中用到的MVP模式
https://blog.csdn.net/weixin_28774815/article/details/80960779
一个文件,一行代码的慢慢debug,才完成的Demo。
先看效果图:
也就是输入用户名:test,密码:1234,点击CLICK,完成登录操作,如果登录成功,弹出登录成功提示,或者弹出登录失败提示。
先与界面布局文件:
然后,再直接从官网将BasePresenter.java和BaseView.java复制过来。
public interface BasePresenter {
void start();
}
public interface BaseView {
void setPresenter(T presenter);
}
再定义一个IModel接口:
public interface IModel {
}
然后实现LoginMode类,主要是实现一个登录的操作:
public class LoginMode implements IModel {
private String mUserName = "test";
private String mPassWord = "1234";
private LoginLisentener loginLisentener;
public void login(String username, String password) {
if (loginLisentener == null) {
return;
}
if (mUserName.equals(username) && mPassWord.equals(password)){
loginLisentener.onSeccess();
} else {
loginLisentener.onFails();
}
}
public void setLoginLisentener(LoginLisentener loginLisentener) {
this.loginLisentener = loginLisentener;
}
public interface LoginLisentener {
void onSeccess();
void onFails();
}
}
下面再实现一个LoginContract类,这就是官方说的契约类。
在这个类中, 我们定义了View 接口,主要有二个接口,分别来表示登录时成功和失败的界面相关的操作。
再定义了Presenter 接口,主要是为了执行登录操作的总入口。
public class LoginContract {
public interface View extends BaseView {
void onLoginSeccess();
void onLoginFails();
}
public interface Presenter extends BasePresenter {
void onLogin(String name, String password);
}
}
下面就是我们的核心类LoginPresenter,一般来说view和model都是其成员方法,一个构造方法,还有就是其定义的核心登录操作接口onLogin,而start一般就是实现一些初始化操作:
public class LoginPresenter implements LoginContract.Presenter{
private static final String TAG = "LoginPresenter";
private final LoginContract.View mView;
private LoginMode loginMode;
public LoginPresenter(final LoginContract.View mView) {
this.mView = mView;
this.loginMode = new LoginMode();
loginMode.setLoginLisentener(new LoginMode.LoginLisentener() {
@Override
public void onSeccess() {
mView.onLoginSeccess();
}
@Override
public void onFails() {
mView.onLoginFails();
}
});
}
@Override
public void onLogin(String name, String password) {
loginMode.login(name, password);
}
@Override
public void start() {
Log.i(TAG,"start");
}
}
而最后,在MVPDemoMainActivity界面登录时,我们就是只要调用:loginPresenter.onLogin(getUserName(),getPassword());
就可以完成登录的逻辑了。
public class MVPDemoMainActivity extends AppCompatActivity implements LoginContract.View{
private static final String TAG = "MVPDemoMainActivity";
private EditText user_name;
private EditText password;
private Button button;
private LoginContract.Presenter loginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvpdemo_main);
init();
}
private void init() {
user_name = (EditText) findViewById(R.id.user_name);
password = (EditText) findViewById(R.id.password);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
loginPresenter.onLogin(getUserName(),getPassword());
}
});
loginPresenter = new LoginPresenter(this);
loginPresenter.start();
}
private String getUserName(){
return user_name.getText().toString();
}
private String getPassword(){
return password.getText().toString();
}
@Override
public void onLoginSeccess() {
Toast.makeText(getApplicationContext(), "登陆成功!", Toast.LENGTH_LONG).show();
Log.i(TAG,"onLoginSeccess");
}
@Override
public void onLoginFails() {
Toast.makeText(getApplicationContext(), "登陆失败!", Toast.LENGTH_LONG).show();
Log.i(TAG,"onLoginFails");
}
@Override
public void setPresenter(LoginContract.Presenter presenter) {
loginPresenter = presenter;
}
@Override
protected void onDestroy() {
super.onDestroy();
this.loginPresenter = null;
}
}
从最简单的Android MVP讲起
https://www.jianshu.com/p/4736ebe1114b
我们参考上面这个例子,来实现一个mvp+okhttp的例子
添加库依赖 app\build.gradle
dependencies {
implementation("com.squareup.okhttp3:okhttp:3.14.1")
implementation("com.squareup.okio:okio:2.2.2")
}
在AndroidManifest.xml文件中添加网络权限
MainView.java代码:
public interface MainView {
void getMessage(String message);
void error();
}
MainModel.java代码
public class MainModel {
public Call getData(String url) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
return client.newCall(request);
}
}
MainPresenter.java代码:
public class MainPresenter {
private MainView mainView;
private MainModel model;
public MainPresenter(MainView mainView) {
this.mainView = mainView;
model=new MainModel();
}
public void getUrlData(String url){
model.getData(url).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
mainView.error();
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
mainView.getMessage(response.body().string());
}
});
}
}
MVPDemo02MainActivity .java
public class MVPDemo02MainActivity extends AppCompatActivity implements MainView{
private TextView resultTextView;
private MyHandler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvpdemo02_main);
init();
}
private void init() {
Button button = (Button)findViewById(R.id.button);
handler = new MyHandler(this);
final EditText editText = (EditText)findViewById(R.id.et_url);
resultTextView = (TextView)findViewById(R.id.tv_result);
final MainPresenter presenter = new MainPresenter(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String url = editText.getText().toString();
presenter.getUrlData(url);
}
});
}
@Override
public void getMessage(String message) {
Message msg = handler.obtainMessage(0, message);
handler.sendMessage(msg);
}
@Override
public void error() {
Message msg = handler.obtainMessage(1, "error");
handler.sendMessage(msg);
}
private static class MyHandler extends Handler {
private WeakReference reference;
private MyHandler(MVPDemo02MainActivity activity) {
reference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MVPDemo02MainActivity activity = reference.get();
switch (msg.what) {
case 0:
activity.resultTextView.setText(msg.obj.toString());
break;
case 1:
activity.resultTextView.setText(msg.obj.toString());
break;
}
}
}
}