一直听群里的人说MVP模式去开发app 自己也搜藏了几篇文章 但一直没事件去学习,正好这两天有空闲的时间就尝试写个demo出来看看。概念信的东西我就不写了 网上的文章对于MVP的概念大致都是一样的。对于新东西 我一般是通过先写出个demo 以后在运用的过程再去学习此东西里面的详细内容。
建立MVP 项目 一般需要 建立 view(界面逻辑),model(业务逻辑),presenter(调度)这几个包名。当然项目离不开 bean(实体数据) 基本上这几个包名就能组成 一个基本的MVP框架了 其它的包名根据自己的需要建立
此次demo我采用的rxjava和retrofit来完成线程调度和网络请求 既然是新的不错的东西 为什么不用呢。
最后我的工程结构为
首先从 看看api包里的LoginApi 里面是retrofit的网络请求 非常简单 强烈建议大家使用retrofit 我是看这篇文章学习的
https://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=2653577186&idx=1&sn=1a5f6369faeb22b4b68ea39f25020d28&scene=1&srcid=0605oJ1NiiihvcW5jF8iy3n6&key=f5c31ae61525f82e38a1a943febc987278275256a5df936f1119c6514ebc78df82fc229de80607e2372e4c0f1451e4db&ascene=0&uin=Mjc3OTU3Nzk1&devicetype=iMac+MacBookPro10%2C1+OSX+OSX+10.10.5+build%2814F1808%29&version=11020201&pass_ticket=Yfzg8hN3fuLjjXoQDSG%2BBKWgRxryyVOFVwGFzsu7nB%2FgSZp9gdXJS%2FudxKZSNLan
public interface LoginApi {
@POST("testMvp.aspx")
@FormUrlEncoded
Observable<Response<User>> login(@Field("do") String action, @Field("user_info") String userInfo);
}
base里面封装着基本所有界面和所有业务都需要的方法 这几个类基本不需要做任何修改只需要拷贝到下一个工程 当然你也可以根据需要在里面扩展你想要的方法 关于封装 我借鉴的是
https://github.com/183619962/MVPTest
public class BaseModel {
//retrofit请求数据的管理类
public RetrofitManager retrofitManager;
public BaseModel() {
//初始化retrofit
retrofitManager = RetrofitManager.builder();
}
}
public class BasePresenter <T extends IBaseView,V> implements IBasePresenter, Observer<V> {
public IBaseView iView;
/**
* 构造方法
*
* @param view 具体业务的接口对象
*/
public BasePresenter(T view) {
this.iView = view;
}
@Override
public void onResume() {
}
@Override
public void onDestroy() {
}
@Override
public void onCompleted() {
iView.hideProgress();
}
@Override
public void onError(Throwable e) {
iView.loadDataError(e);
iView.hideProgress();
}
@Override
public void onNext(V t) {
iView.loadDataSuccess(t);
}
}
public interface IBasePresenter {
/**
* 开始<br>
* 用于做一些初始化的操作
*/
void onResume();
/**
* 销毁<br>
* 用于做一些销毁、回收等类型的操作
*/
void onDestroy();
}
public interface IBaseView<T> {
/**
* 显示提示消息
*
* @param msg
*/
void toast(String msg);
/**
* 显示进度
*
* @param progress
*/
void showProgress(int progress);
/**
* 隐藏进度
*/
void hideProgress();
/**
* 请求成功
* @param data
*/
void loadDataSuccess(T data);
/**
* 请求错误
* @param throwable
*/
void loadDataError(Throwable throwable);
/**
* 开始加载
*/
void startLoading();
}
好了 前面的基本工作都做完了 界面该实现真正的功能了
我实现的是登陆功能
我先实现登陆功能的逻辑 也就是先实现LoginModel
首先登陆之前需要初始化 登陆请求接口 然后才是传递参数实现登陆 基本上就这个两点 那么转换成代码就是
public class LoginModel extends BaseModel {
private Context context;
private LoginApi loginApi;
/**
* 初始化登陆请求接口
* @param context
*/
public LoginModel(Context context) {
this.context = context;
loginApi = retrofitManager.getLoginApi();
}
/**
* 实现登陆
* @param userName
* @param pwd
* @param observer
*/
public void login(String userName, String pwd, final Observer observer) {
String userInfo = "{\"name\":\"" + userName + "\"," +
"\"pwd\":\"" + pwd + "\"" +
"}";
loginApi.login("login",userInfo).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Response<User>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
observer.onError(e);
}
@Override
public void onNext(final Response<User> jsonObjectResponse) {
/**
* 延迟一下再返回结果 这样能看到 登陆的动画 可以不用延时直接返回
*/
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (jsonObjectResponse.code() == 200) {
observer.onNext(jsonObjectResponse.body());
observer.onCompleted();
} else {
onError(new Throwable("网络错误"));
}
}
},3000);
}
});
}
}
然后实现VIEW
写之前根据逻辑来分析需要哪些方法 登陆的话 需要 用户名和用户密码 这两个是必须的 接下来可以有 清除密码 清除用户名 等 不必须的方法可以用有可以没有 根据上面的分析可以写出以下代码
/**
* 封装好登陆view方法 让activity(也就是view)去实现它
*/
public interface ILoginView extends IBaseView<User>{
/**
* 获取用户名
* @return
*/
String getUserName();
/**
* 获取用户密码
* @return
*/
String getPwd();
/**
* 清除用户名
*/
void clearnUserName();
/**
* 清除用户密码
*/
void clearnPwd();
}
接下来就是presenter实现调度了
presenter 首先它需要从view(也就是activity)成拿到数据 然后再把数据交给model(也就是业务层去处理) model处理完业务逻辑 返回数据给 presenter 再有presenter 反馈给 view(activity) 根据这个思路 我们需要定义一个LoginModel 和一个IView
public class LoginPresenter extends BasePresenter<ILoginView,User> {
private LoginModel loginModel;
private Context context;
/**
* 构造方法
*
* @param view 具体业务的接口对象
*/
public LoginPresenter(ILoginView view,Context context) {
super(view);
this.context = context;
loginModel = new LoginModel(context);
}
/**
* 登陆
* @param userName
* @param pwd
*/
public void login(String userName,String pwd) {
onResume();
iView.startLoading();
iView.showProgress(0);
loginModel.login(userName,pwd,this);
}
}
注意此处为什么没有定义IView 是因为BasePresenter里已经定义好了一个IBaseView(可以看看上面的 BasePresenter的定义)
子类继承父类的public IBaseView 自然就存在了 当LoginPresenter被初始化时就会初始化IView
最后一步
真正的view(activity)
初始化activity上的控件 控件有 Edittext userName; Edittext pwd; Button login;
view 和presenter进行交互 view把数据交给presenter
[ 然后presenter把数据交给model,model处理数据(登陆服务器 登陆成分返回数据给presenter presenter 反馈给activity 登陆失败model返回给presenter ,presenter反馈给activity) ] 中括号里的不走 由前面我们定义好的逻辑自动实现
public class LoginActivity extends BaseActivity implements ILoginView {
@BindView(R.id.editText)
EditText userName;
@BindView(R.id.editText2)
EditText pwd;
@BindView(R.id.button)
Button login;
@BindView(R.id.loginNotice)
RelativeLayout loginNotice;
private LoginPresenter loginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState,R.layout.activity_login);
loginPresenter = new LoginPresenter(this, this);
}
@Override
public String getUserName() {
return userName.getText().toString();
}
@Override
public String getPwd() {
return pwd.getText().toString();
}
@Override
public void clearnUserName() {
}
@Override
public void clearnPwd() {
}
@Override
public void toast(String msg) {
}
@Override
public void showProgress(int progress) {
loginNotice.setVisibility(View.VISIBLE);
}
@Override
public void hideProgress() {
loginNotice.setVisibility(View.GONE);
}
/**
* 请求成功
*
* @param data
*/
@Override
public void loadDataSuccess(User data) {
if (data.isMessageStatus()) {
Toast.makeText(LoginActivity.this, "登陆成功!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LoginActivity.this, "登陆失败!" + data.getMessage(), Toast.LENGTH_SHORT).show();
}
}
/**
* 请求错误
*
* @param throwable
*/
@Override
public void loadDataError(Throwable throwable) {
throwable.printStackTrace();
Toast.makeText(LoginActivity.this, "登陆失败!", Toast.LENGTH_SHORT).show();
}
/**
* 开始加载
*/
@Override
public void startLoading() {
Log.e(TAG,"开始登陆");
}
@OnClick(R.id.button)
public void onClick() {
loginPresenter.login(getUserName(), getPwd());
}
}
好了一个mvp的登陆功能就完成 实现更多的功能只需要 按照上面的步骤实现 model 实现IView 实现 presenter 再通过view(activity) 进行调度就行了
本文采用的是 butterknife 有更好的 dragger2 和databinding 深度解耦
此篇文章 我只是从我学习的角度写出来的 有写错的地方请给出意见 如果是大神请飘过
3933

被折叠的 条评论
为什么被折叠?



