王学岗csdn——MVP架构模式详解(一)

前面我写过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,我们继续完善;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值