王学岗csdn——MVP架构模式详解(一)
来源:互联网 发布:python的素数怎么表示 编辑:程序博客网 时间:2024/06/02 02:41
前面我写过MVP模式,但是过于浅显,今天我在来详细的探究下该模式
1、什么是MVP? 通俗讲解:就是通过Presenter将View和Mode解耦 M(模型)->Model(模型)包括:与数据相关都属于M层(例如:数据库、文件、网络、数据解析、数据保存等等......)bean也属于M层,但M层不单单指M层 V->View包括:在MVC中View只是一个单纯视图,但是在MVP中(例如:Activity、Fragment、布局),即:与UI相关都属于V层 P->Presenter包括:调度,通过P层将我们的View层和Model进行关联转换,将M转换为V,同时使M和V解耦 2、MVP和Java设计模式有什么区别? 举例说明:北京鸟巢(整体架构)---MVP---范围大而广 窗户设计、场地设计、跑到设计、座位设计等等......---相当于设计模式---针对具体的问题或者说场景提出不同解决方案大家思考下,如果你连鸟巢整体架构都没有,那你单单弄一个窗户设计有意义吗? 3、MVP架构交互流程? 4、案例分析?---登录为例
我们看下使用MVP如何实现一个简单的网络登录
首先看下各个类名
三个Utils类,这三个类实现了网络的请求,当然你完全可以换成OKHttp请求或者Retrofit
package com.example.acer.myfirstmvp.utils;import android.os.AsyncTask;public class HttpTask extends AsyncTask<String, Void, String> { private HttpUtils.OnHttpResultListener onHttpResultListener; public HttpTask(HttpUtils.OnHttpResultListener onHttpResultListener) { this.onHttpResultListener = onHttpResultListener; } @Override protected String doInBackground(String... params) { try { return HttpUtils.post(params[0], params[1], params[2]); } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(String result) { if (this.onHttpResultListener != null) { this.onHttpResultListener.onResult(result); } }}
package com.example.acer.myfirstmvp.utils;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.InputStream;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;public class HttpUtils { public static final String URL_STR = "http://192.168.57.1:8080/Dream_4_23_PhoneGapServer/PhoneGapServlet"; public static String get(String urlStr) { String result = null; try { URL url = new URL(urlStr); HttpURLConnection connection = (HttpURLConnection) url .openConnection(); connection.setReadTimeout(5000); connection.setRequestMethod("GET"); connection.setDoInput(true); if (connection.getResponseCode() == 200) { InputStream inStream = connection.getInputStream(); result = new String(StreamTool.readInputStream(inStream)); return result; } } catch (Exception e) { e.printStackTrace(); } return result; } public static String post(String urlStr, String username, String password) throws Exception { StringBuffer sb = null; String param = "username=" + username + "&password=" + password; URL url = new URL(urlStr); HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); // 设置参数 httpConn.setDoOutput(true); // 需要输出 httpConn.setDoInput(true); // 需要输入 httpConn.setUseCaches(false); // 不允许缓存 httpConn.setRequestMethod("POST"); // 设置POST方式连接 // 设置请求属性 httpConn.setRequestProperty("Charset", "UTF-8"); // 连接,也可以不用明文connect,使用下面的httpConn.getOutputStream()会自动connect httpConn.connect(); // 建立输入流,向指向的URL传入参数 DataOutputStream dos = new DataOutputStream(httpConn.getOutputStream()); dos.writeBytes(param.toString()); dos.flush(); dos.close(); // 获得响应状态 int resultCode = httpConn.getResponseCode(); sb = new StringBuffer(); if (HttpURLConnection.HTTP_OK == resultCode) { String readLine = new String(); //解析网络请求数据 BufferedReader responseReader = new BufferedReader( new InputStreamReader(httpConn.getInputStream(), "UTF-8")); while ((readLine = responseReader.readLine()) != null) { sb.append(readLine).append("\n"); } responseReader.close(); return sb.toString(); } return null; } public interface OnHttpResultListener { public void onResult(String result); }}
package com.example.acer.myfirstmvp.utils;import java.io.ByteArrayOutputStream;import java.io.InputStream;public class StreamTool { /** * 从输入流中读取数据 * @param inStream * @return * @throws Exception */ public static byte[] readInputStream(InputStream inStream) throws Exception{ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while( (len = inStream.read(buffer)) !=-1 ){ outStream.write(buffer, 0, len); } byte[] data = outStream.toByteArray();//网页的二进制数据 outStream.close(); inStream.close(); return data; }}
三个没用的类贴完了,下面我们来贴出我们的MVP相关的类,在代码中都做注释了,这里就不废话了,代码很简单;
M类,
package com.example.acer.myfirstmvp.simple2;import com.example.acer.myfirstmvp.utils.HttpTask;import com.example.acer.myfirstmvp.utils.HttpUtils;/** * M层(数据网络都在这一层) */public class MainModel { public void login(String username, String pwd, final HttpUtils.OnHttpResultListener onHttpResultListener){ HttpTask httpTask=new HttpTask(new HttpUtils.OnHttpResultListener() { @Override public void onResult(String result) { //解析数据 //更新UI onHttpResultListener.onResult(result); } }); httpTask.execute(username,pwd,"http://www.baidu.com"); }}
V类,首先要有一个接口
package com.example.acer.myfirstmvp.simple2;/** * View接口,通过View暴露接口去访问 */public interface MainView { public void onLoginResult(String result);}
package com.example.acer.myfirstmvp.simple2;import android.os.Bundle;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.View;import android.widget.Toast;import com.example.acer.myfirstmvp.R;/** * MVPP将View(本例子中的Activity)和相关操作进行了完全的隔离,将来你修改网络请求方式(比如修改成OKhttp),丝毫不影响UI,UI只需要 * 通过onLoginResult拿到该结果;更加方便团队开发,大大提高了开发效率 */public class MainActivity2 extends AppCompatActivity implements MainView{private MainPresenter mMainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); mMainPresenter=new MainPresenter(this); } public void click(View v){ this.mMainPresenter.login("Dream","123"); } @Override public void onLoginResult(String result) { //更新UI Toast.makeText(this,result,Toast.LENGTH_LONG).show(); }}
p类,关键的类
package com.example.acer.myfirstmvp.simple2;import com.example.acer.myfirstmvp.utils.HttpUtils;/** * P层,对M和V进行关联 */public class MainPresenter { private MainView mainView; private MainModel maiModel; public MainPresenter(MainView mainView){ this.maiModel=new MainModel(); this.mainView=mainView; } public void login(String username,String pwd){ this.maiModel.login(username, pwd, new HttpUtils.OnHttpResultListener() { @Override public void onResult(String result) { mainView.onLoginResult(result); } }); }}
当然这个例子太简单,实际开发中没毛线用;举个两个例子
问题一: 假设:Activity意外关闭,这个时候网络请求还在进行,当数据返回的时候,发现Activity挂掉了?(或者说Fragment)---挂掉了你还要回调,这可是一个垃圾操作啊 该怎么办?---解决办法:提供一个销毁的方法
大家看下我们的解决方案
首先修改下P
package com.example.acer.myfirstmvp.simple3;import com.example.acer.myfirstmvp.utils.HttpUtils;/** * P层,对M和V进行关联 */public class MainPresenter { private MainView mainView; private MainModel maiModel; // public MainPresenter(MainView mainView){ // this.maiModel=new MainModel(); // this.mainView=mainView; // } //改动的地方 **public MainPresenter() { //改动的地方 this.maiModel = new MainModel(); }** public void login(String username, String pwd) { this.maiModel.login(username, pwd, new HttpUtils.OnHttpResultListener() { @Override public void onResult(String result) { if (mainView != null) { mainView.onLoginResult(result); } } }); } **//改动的地方 //绑定视图层 public void attachView(MainView mainView) { this.mainView = mainView; } //改动的地方 //解除绑定 public void detachView() { this.mainView = null; }**}
P增加了两个方法(绑定和解除绑定的方法),同时修改下M层
package com.example.acer.myfirstmvp.simple3;import android.os.Bundle;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.View;import android.widget.Toast;import com.example.acer.myfirstmvp.R;/** * MVPP将View(本例子中的Activity)和相关操作进行了完全的隔离,将来你修改网络请求方式(比如修改成OKhttp),丝毫不影响UI,UI只需要 * 通过onLoginResult拿到该结果;更加方便团队开发,大大提高了开发效率 */public class MainActivity2 extends AppCompatActivity implements MainView {private MainPresenter mMainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); **//修改的地方// mMainPresenter=new MainPresenter(this); mMainPresenter=new MainPresenter(); this.mMainPresenter.attachView(this);** } public void click(View v){ this.mMainPresenter.login("Dream","123"); } @Override public void onLoginResult(String result) { //更新UI Toast.makeText(this,result,Toast.LENGTH_LONG).show(); } **//修改的地方 @Override protected void onDestroy() { super.onDestroy(); this.mMainPresenter.detachView(); }**}
但我们这样依然不完美,举个例子
项目开发当中Activity数量,或者说Fragment数量很庞大,这样会有很多代码冗余 该怎么办?---解决方案:单独抽象出来(引出抽象类)
下面我们看下,抽象类如何设计MVP
先看下类的结构
package com.tz.architect.mvp.simple4;import android.os.Bundle;import android.view.View;import android.widget.Toast;import com.tz.architect.mvp.R;import com.tz.architect.mvp.simple4.framework.impl.MainPresenter;import com.tz.architect.mvp.simple4.framework.impl.MainView;import com.tz.architect.mvp.simple4.framework.impl.MvpActivity;public class MainActivity extends MvpActivity<MainView, MainPresenter> implements MainView { @Override public MainPresenter bindPresenter() { return new MainPresenter(); } @Override public MainView bindView() { return this; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } // 其实在Android当中,本身就是一个非常典型MVC架构 // 在Android MVC中 // M代表:数据 // C代表: activity或者Fragment // V代表:视图 // MVP适合大项目 // MVP更加便于团队开发 public void click(View v) { getPresenter().login("Dream", "123456"); } @Override public void onLoginResult(String result) { // 更新UI Toast.makeText(this, result, Toast.LENGTH_LONG).show(); }}
package com.tz.architect.mvp.simple4.framework;public abstract class AbsMvpPresenter<V extends IMvpView> { private V view; public V getView() { return view; } /** * 绑定 * * @param view */ public void attachView(V view) { this.view = view; } /** * 解除绑定 */ public void detachView() { this.view = null; }}
package com.tz.architect.mvp.simple4.framework;public interface IMvpView {}
package com.tz.architect.mvp.simple4.framework.impl;import com.tz.architect.mvp.utils.HttpTask;import com.tz.architect.mvp.utils.HttpUtils.OnHttpResultListener;/** * M层(数据、网络) * @author Dream * */public class MainModel { public void login(String username,String pwd,final OnHttpResultListener onHttpResultListener){ HttpTask httpTask = new HttpTask(new OnHttpResultListener() { @Override public void onResult(String result) { onHttpResultListener.onResult(result); } }); httpTask.execute(username,pwd,"http://www.baidu.com"); }}
package com.tz.architect.mvp.simple4.framework.impl;import com.tz.architect.mvp.simple4.framework.AbsMvpPresenter;import com.tz.architect.mvp.utils.HttpUtils.OnHttpResultListener;/** * P层 * * @author Dream * */public class MainPresenter extends AbsMvpPresenter<MainView> { private MainModel mainModel; public MainPresenter() { this.mainModel = new MainModel(); } public void login(String username, String pwd) { this.mainModel.login(username, pwd, new OnHttpResultListener() { @Override public void onResult(String result) { if (getView() != null) { getView().onLoginResult(result); } } }); }}
package com.tz.architect.mvp.simple4.framework.impl;import com.tz.architect.mvp.simple4.framework.IMvpView;/** * View接口 * @author Dream * */public interface MainView extends IMvpView{ public void onLoginResult(String result);}
package com.tz.architect.mvp.simple4.framework.impl;import com.tz.architect.mvp.simple4.framework.AbsMvpPresenter;import com.tz.architect.mvp.simple4.framework.IMvpView;import android.app.Activity;import android.os.Bundle;public abstract class MvpActivity<V extends IMvpView, P extends AbsMvpPresenter<V>> extends Activity { private P presenter; private V view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (presenter == null) { this.presenter = bindPresenter(); } if (view == null) { this.view = bindView(); this.presenter.attachView(this.view); } } /** * 绑定P层 * * @return */ public abstract P bindPresenter(); /** * 绑定View层 * * @return */ public abstract V bindView(); public P getPresenter() { return presenter; } public V getView() { return view; } @Override protected void onDestroy() { super.onDestroy(); if (this.presenter != null) { this.presenter.detachView(); } }}
即便如此,这个框架仍然不完整,因为我们这里只有Activity而缺少Fragment,我们继续完善;
阅读全文
0 0
- 王学岗csdn——MVP架构模式详解(一)
- MVP架构模式详解
- MVP架构模式详解
- Android MVP 架构模式详解
- Android中MVP架构模式详解
- Android Mvp+DataBinding架构模式详解
- Android MVP开发模式 google 官方Mvp架构详解
- 架构探险——Android MVP模式浅析
- Android——MVP架构模式之入门demo
- iOS架构初探 (一)—— MVC与MVP
- MVP架构模式
- android-MVP架构模式
- mvp架构模式
- mvp架构模式
- MVP架构模式
- 细谈MVP架构模式
- Android|MVP架构模式
- MVP应用架构模式
- 【笔记】SSD: Single Shot MultiBox Detector
- codeM 初赛b轮 子串
- markdown编写入门
- JSP中四种传递参数的方法
- 【Tools】ubuntu下的串口大器--minicom
- 王学岗csdn——MVP架构模式详解(一)
- LintCode_463_整数排序
- Pythondatetime模块中datetime类的使用
- 读写Cookie实现免输入
- leetcode之Two Sum问题
- centos6.5安装spark2
- 【C#】值类型和引用类型
- MySQL5 学习笔记--数据记录基本操作
- Redis的补充---持久化和主从复制