什么是MVP?
MVP设计模式有大量的的博客去讲解,我今天还是要讲讲什么是MVP模式因为想让自己有个更加深刻理解,再加上自己最近看了项目发现和Java中的泛型结合可以让整个MVP模式代码更加优雅和简洁,好了现在说正题了MVP.
M:数据提供层:Model 一般由请求网络类或者数据库等组成。
V :数据展示层:View activity,fragment组成
P:业务逻辑层:Presenter 处理Model View之间逻辑代码组成
MVP关系图:
上面的图已经很好说明Model View Presenter 三者之间的关系我就不都说了
讲讲T-MVP肯定要用举例子才更好理解它,那我就用登录这个功能来讲讲MVP模式吧!
目录结构
我们来看下基类包中
首先baseModel接口
可以看到并没有任何代码 由于这个小项目所以一部涉及 Model 抽取
BasePresenter类
public abstract class BasePresenter <V,M>{
public V mView;
public M mModel;
public void setVM(V view,M modle){
this.mView=view;
this.mModel=modle;
}
}
BaseView接口
public interface BaseView {
//请求开始调用
void RequstStart();
//请求结束调用
void ReqeustEnd();
//网络错误的方法
void onInternetError();
//请求错误的方法
void ReqeustError();
}
看完MVP基类 , 发现在Presenter 会有二元组泛型 这个就是泛型和MVP结合精华所在,
现在再看BaseActivity
public abstract class BaseActivity<P extends BasePresenter,M extends BaseModel > extends AppCompatActivity implements BaseView {
public P mPresenter;
public M mBaseModel;
public Activity mActivity;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentView());
System.out.println("BaseActivity.onCreate");
mPresenter= CommUtils.getT(this,0);
mBaseModel=CommUtils.getT(this,1);
if(this instanceof BaseView){
mPresenter.setVM(this,mBaseModel);
}
mActivity=this;
init();
initView();
initData();
}
/**
* 初始化变量
*/
public abstract void init();
/**
* 初始化控件
*/
public abstract void initView();
/**
* 初始化数据
*/
public abstract void initData();
/**
* 获得activity布局文件
* @return
*/
public abstract int getContentView();
}
介绍完基类就来看 具体实现吧
/**
* Created by Administrator on 2016/12/14.
* 管理登录接口类 作用:统一管理,减少类在包中
*/
public interface LoginContract {
interface View extends BaseView{
String getUserName(EditText editText);
String getPassWorld(EditText editText);
}
interface Model extends BaseModel{
void login(String userName,String passWorld,LoginListener listener);
}
abstract class Presenter extends BasePresenter<View, Model>{
public abstract void login(Context context,String userName,String passWorld ,LoginListener listener);
}
interface LoginListener{
void loginSuccess();
void loginFail();
}
}
loginModel 具体实现类
/**
* Created by Administrator on 2016/12/14.
* 数据提供层
*/
public class LoginModel implements LoginContract.Model{
private Handler mHandler=new Handler(Looper.getMainLooper());
@Override
public void login(final String userName,final String passWorld, final LoginContract.LoginListener listener) {
/**
* 模拟网路请求
*/
new Thread(){
@Override
public void run() {
if(userName.equals("jack")&&passWorld.equals("123456")){
System.out.println("登录成功");
}
try {
Thread.sleep(1*1000);
//回调到主线程中
mHandler.post(new Runnable() {
@Override
public void run() {
listener.loginSuccess();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
mHandler.post(new Runnable() {
@Override
public void run() {
listener.loginFail();
}
});
}
}
}.start();
}
}
LoginPresenter
/**
* Created by Administrator on 2016/12/14.
* 业务逻辑控制层
*/
public class LoginPresenter extends LoginContract.Presenter {
@Override
public void login(Context context, String userName, String passWorld ,LoginContract.LoginListener loginListener) {
mView.RequstStart();
mModel.login(userName,passWorld,loginListener);
}
}
LoginActivity
public class LoginActivity extends BaseActivity<LoginPresenter,LoginModel> implements LoginContract.View{
EditText mEtUserName;
EditText mEtPassWorld;
Button mBtnLogin;
private AlertDialog.Builder mBuilder;
private AlertDialog mDialog;
@Override
public void init() {
mBuilder = new android.support.v7.app.AlertDialog.Builder(this);
mBuilder.setTitle("登录");
mBuilder.setMessage("正在登录 请稍等");
}
@Override
public void initView() {
mBtnLogin= (Button) this.findViewById(R.id.btn_login);
mEtUserName= (EditText) this.findViewById(R.id.et_userName);
mEtPassWorld= (EditText) this.findViewById(R.id.et_passWorld);
}
@Override
public void initData() {
mBtnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String userName=getUserName(mEtUserName);
String passWorld=getPassWorld(mEtPassWorld);
if (userName==null||userName.equals("")){
Toast.makeText(mActivity,"用户名为空,请填写",Toast.LENGTH_SHORT).show();
return;
}
if (passWorld==null||passWorld.equals("")){
Toast.makeText(mActivity,"密码为空,请填写!",Toast.LENGTH_SHORT).show();
return;
}
mPresenter.login(mActivity, userName, passWorld, new LoginContract.LoginListener() {
@Override
public void loginSuccess() {
Toast.makeText(mActivity,"登录成功了",Toast.LENGTH_SHORT).show();
ReqeustEnd();
}
@Override
public void loginFail() {
Toast.makeText(mActivity,"登录失败",Toast.LENGTH_SHORT).show();
ReqeustEnd();
}
});
}
});
}
@Override
public void RequstStart() {
mDialog= mBuilder.show();
}
@Override
public void ReqeustEnd() {
mDialog.dismiss();
}
@Override
public void onInternetError() {
}
@Override
public void ReqeustError() {
}
@Override
public int getContentView() {
return R.layout.activity_main;
}
@Override
public String getUserName(EditText editText) {
String userName=null;
if(editText!=null){
userName= editText.getText().toString().trim();
}
return userName;
}
@Override
public String getPassWorld(EditText editText) {
String passWorld =null;
if(editText!=null){
passWorld= editText.getText().toString().trim();
}
return passWorld;
}
}
CommUtils
public class CommUtils {
public static <T> T getT(Object o, int i) {
try {
return ((Class<T>) ((ParameterizedType) (o.getClass()
.getGenericSuperclass())).getActualTypeArguments()[i])
.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
}
return null;
}
}
最后把布局文件代码贴下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.jack.test.LoginActivity">
<TextView
android:layout_width="match_parent"
android:text="用户名:"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/et_userName"
android:layout_width="match_parent"
android:hint="请输入用户名"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:text="密 码:"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/et_passWorld"
android:layout_width="match_parent"
android:hint="请输入你密码"
android:password="true"
android:inputType="textPassword"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_login"
android:text="登录"
android:textSize="16sp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
项目运行图
讲解的不多 相信大家看代码就会懂 如果还要什么错误或者很好的建议请留言