初学MVP
来源:互联网 发布:同性电影推荐知乎 编辑:程序博客网 时间:2024/03/28 23:31
一直听群里的人说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 深度解耦
此篇文章 我只是从我学习的角度写出来的 有写错的地方请给出意见 如果是大神请飘过
- 初学MVP
- 初学Kotlin MVP+Retofit2+Rxjava2
- MVP
- MVP
- MVP
- MVP
- MVP
- MVP
- MVP
- MVP
- mvp
- MVP
- MVP
- mvp
- MVP
- MVP
- MVP
- MVP
- Android开发-layout布局相关属性总结
- GDB arm-linux交叉编译移植和使用方法(特别是对于正在运行的程序或者段错误的程序进行分析)
- LeetCode第54题之Spiral Matrix
- iOS适配那些事
- ARC基本原理
- 初学MVP
- Java下载文件,文件名中文乱码问题
- Hibernate环境框架搭建
- HDOJ 3923 Invoker
- 使用 Intel HAXM 为 Android 模拟器加速,媲美真机
- android开发—第一步:android开发环境搭建
- C#/JAVA/PHP 互通DES加解密算法(ECB模式支持8位)
- Problem-F
- 字典树(Trie树)算法