本blog介绍mvp模式的特点与优点,为了方便理解 举了用mvp模式实现的两个例子,例一偏向简单用于原理说明,例二应用现在比较火的Retrofit和RXJava进行网络数据请求的mvp模式实例。
1、MVP模式:
2、MVP模式 VS MVC模式
(1)各个层之间通过接口协议进行沟通。
(2)View和Model不再进行直接交互
3、MVP优势:
(1)View和Model之间的耦合度降低,使各自更关注自身业务。
(2)便于单元测试。
(3)代码复用率提高。
(4)代码框架更适用于快速迭代开发。
4、-----------------------------实例1
项目结构:
View层:
public class BaseViewActivity extends AppCompatActivity implements BaseView{
private BasePresenterImpl mPresenter;
boolean flag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPresenter = new BasePresenterImpl(this);
Log.e("JS","进入 view 层 1");
//开始请求服务
mPresenter.loadData();
Log.e("JS","进入 view 层 2");
//加载完成
mPresenter.loadResult();
}
@Override
public void loading() {
Log.e("JS","开启 进入view层 iterface 事件");
}
@Override
public void cancelLoading() {
Log.e("JS","结束 进入view层 iterface 事件");
}
}
//UI逻辑接口,一般由activity、fragment实现
public interface BaseView {
//显示加载进度
void loading();
//隐藏加载进度
void cancelLoading();
}
public class BasePresenterImpl implements BasePresenter{
private BaseView mView;
private BaseModel mModel;
public BasePresenterImpl(BaseView view){
mModel = new BaseModelimpl();
this.mView = view;
}
// 调用view层和model层来 加载数据
public void loadData(){
Log.e("JS","model/view------->presenter ");
mView.loading();//访问view层
mModel.RequestService();//访问model层
Log.e("JS","-----可得到 view和model return 的数据-------");
}
@Override
public void loadResult() {
Log.e("JS","presenter ---------> view ");
mView.cancelLoading();
}
}
/**处理业务逻辑
* Created by apple on 17/4/27.
*/
public interface BasePresenter {
//加载数据结果
void loadResult();
}
public class BaseModelimpl implements BaseModel {
@Override
public void RequestService() {
Log.e("JS","开启 进入model层 interface");
}
}
public interface BaseModel {
//请求服务器
void RequestService();
}
打印信息:
实例2-----------------
retrofit和rxJava结合的mvp实例
1、view层接口
import com.example.apple.retrofit.MVP.bean.IpBean;
/**
* Created by apple on 17/5/4.
*/
public interface interView {
public void showInfo(IpBean ipBean);
public void showError(Throwable e);
}
import com.example.apple.retrofit.MVP.bean.IpBean;
import com.example.apple.retrofit.MVP.presenter.Presenter;
import com.example.apple.retrofit.MVP.presenter.interPresenter;
import com.example.apple.retrofit.R;
/**
* Created by apple on 17/5/4.
*/
public class MainActivity extends Activity implements interView{
private TextView ipInfo;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ipInfo = (TextView) findViewById(R.id.ipInfo);
interPresenter presenter = new Presenter(this);
presenter.queryIpInfo("121.33.6.228");//调用presenter层的接口方法
}
@Override
public void showInfo(IpBean ipBean) {
String aa = ipBean.area+ipBean.city+ipBean.country+ipBean.ip+ipBean.region;
Log.e("jj",aa);
ipInfo.setText(aa);
}
@Override
public void showError(Throwable e) {
}
}
public interface interPresenter {
public void queryIpInfo(String ip);
}
public class Presenter implements interPresenter{
//在presenter层,引入model层和view层。
private interView viewActivity;
private interModel model;
public Presenter(MainActivity viewActivity){
this.viewActivity = viewActivity;
model = new Model();
}
@Override
public void queryIpInfo(String ip) {
//观察者位于presenter层,通知主线程
Subscriber<ApiBean<IpBean>> mySubscriber = new Subscriber<ApiBean<IpBean>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
viewActivity.showError(e);
}
@Override
public void onNext(ApiBean<IpBean> ipBeanApiBean) {
//获取来自被观察者model层传来的ipBeanApiBean,并调用view层方法
viewActivity.showInfo(ipBeanApiBean.data);
}
};
model.queryIpInfo(ip,mySubscriber);//调用model接口方法
}
}
3、model层接口
public interface interModel {
public void queryIpInfo(String ip, Subscriber<ApiBean<IpBean>> subscriber);
}
public interface InterfRetrofit {
@GET("service/getIpInfo.php")
Call<ApiBean<IpBean>> getMessage(@Query("ip") String ip);
}
public class Model implements interModel{
@Override
public void queryIpInfo(final String ip, Subscriber<ApiBean<IpBean>> subscriber) {
//被观察者做耗时操作,位于model层
Observable<ApiBean<IpBean>> myObserverble =
Observable.create(new Observable.OnSubscribe<ApiBean<IpBean>>() {
@Override
public void call(Subscriber<? super ApiBean<IpBean>> subscriber) {
//在rxjava的observable中,添加一个retrofit,进行网络请求 具体耗时操作由它执行
String URL_BASE = "http://ip.taobao.com";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL_BASE)
.addConverterFactory(GsonConverterFactory.create())
.build();
InterfRetrofit interfRetrofit = retrofit.create(InterfRetrofit.class);
Call<ApiBean<IpBean>> call = interfRetrofit.getMessage(ip);
try {
Response<ApiBean<IpBean>> response = call.execute();
ApiBean<IpBean> apiResponse = response.body();
//将apiResponse传给观察者presenter
subscriber.onNext(apiResponse);
} catch (IOException e) {
e.printStackTrace();
subscriber.onError(e);
}finally {
subscriber.onCompleted();
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
myObserverble.subscribe(subscriber);
}
}
public class ApiBean<T> implements Serializable {
//结果
public int code;
//数据
public T data;
}
import com.google.gson.annotations.SerializedName;
public class IpBean {
//国家
public String country;
//国家代码
@SerializedName("country_id")
public String countryId;
//地区
public String area;
//地区代码
@SerializedName("area_id")
public String areaId;
//省份
public String region;
//省份代码
@SerializedName("region_id")
public String regionId;
//城市
public String city;
//城市代码
@SerializedName("city_id")
public String cityId;
//区
public String county;
//区号
@SerializedName("county_id")
public String countyId;
//运营商
public String isp;
//运营商代码
@SerializedName("isp_id")
public String ispId;
//IP地址
public String ip;
}
最近在Kindle上读了范冰的《增长黑客》,对增长黑客有了更系统的了解。联想到我自己的微信公众号hacker-thinking和独立博客blog.coderzh.com,我也在苦苦寻找用户增长的终极奥义。我也尝试过各种SEO(搜索引擎优化),比如规范链接地址、nofollow防止权重降低、提供sitemap、增加关键词、规范robots.txt、加快访问速度、增加反向链接等等。肯定有人会说,这些东
SpringDataJpa的扩展继承JpaSpecificationExecutor继承JpaSpecificationExecutordao层public interface PersonDao extends JpaRepository<Person,Integer>, JpaSpecificationExecutor<Person> {}案例测试1单条件 /* * 根据条件,查询单个对象 * */ @Test publ
有一个表名为tb,字段段名为name,数据类型nchar(20)。1、假设字段数据为空,则不管改为什么字段类型,可以直接执行:alter table tb modify (name nvarchar2(40));2、假设字段有数据,则改为varchar2(40)执行时会弹出:“ORA-01439:要更改数据类型,则要修改的列必须为空”,这时要用下面方法来解决这个问题:--修改原字段...
一、ElasticsearchElasticsearch (ES)是一个基于Lucene构建的开源、分布式、RESTful 接口全文搜索引擎。Elasticsearch 还是一个分布式文档数据库,其中每个字段均是被索引的数据且可被搜索,它能够扩展至数以百计的服务器存储以及处理PB级的数据。它可以在很短的时间内在储、搜索和分析大量的数据。它通常作为具有复杂搜索场景情况下的核心发动机。Elasticsearch就是为高可用和可扩展而生的。可以通过购置性能更强的服务器来完成。在本专栏的前几篇文章中我们介绍过
BZOJ2086 POI2010 Blocks
差分演化算法(Differential Evolution)是曾经一度非常热门的算法,该算法简单易用,收敛速度快。这篇文章对其进行总结。算法简介所谓的演化算法是一种自适应,并行的全局优化算法,还包括遗传算法等。差分演化算法与其他演化算法的最大区别在与差分变异算子的应用。差分演化算法主要用于求解实数优化问题,一般不用于求解离散问题。算法流程算法流程图如下。...
北京时间 9 月 23 日凌晨,React 团队发布了关于全新 JSX 转换的博客,同时发布了 React 17 的 RC 版本,新的 JSX 转换不再依赖 React 环境,在转换时会自动引入新的 runtime。 原文链接:https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html 作者:Luna Ru...
如果单独看《Head First 设计模式》中介绍的23种设计模式,单例模式和工厂模式普通开发工程师能够理解,其他模式UML类画的就较为抽象,实现起来并没有那么复杂,只不过要用图形来展现,显的专业的话,就有些麻烦。但是80%的开发工程师能够容易理解吗,我认为大多数人知道继承和实现,就通过这两种方式组合,已经说命了很多问题。古人发明四柱八字,子平讲十神定位,如果通过计算机来实现子平的模型,按照梁湘...
很多博客文末都会有支付宝"向他付款"链接,点击进去后生成定额付款收款链接。这个是怎么实现的呢,其实很简单。将下面的代码复制到博客html下,保存即可。&lt;div id="zanzhu"&gt;&lt;center&gt;&lt;form class="form123" accept-charset="GBK" action="https://shenghuo.alipay.c
家里用的是D-link路由器,不超过100块那种。由于路由器年代久远,偶尔会抽风连不了外网,这时就需要重启路由器。一般常规的做法一是断电重启;二是登陆路由器系统设置选项进行重启。有时路由器离电脑太远了不想跑过去断电,登陆路由器又有点烦锁,什么打开浏览器输入用户名密码找到系统设置选项再点击重启。于是就设想写个python脚本,直接双击或者快捷键打开马上重启路由器。用python来模拟人员登陆路由器设...
You are provided with a BCD one-digit adder namedbcd_faddthat adds two BCD digits and carry-in, and produces a sum and carry-out.module bcd_fadd { input [3:0] a, input [3:0] b, input cin, output cout, output [3:0] sum );In..
verilog笔记_generate使用generate时必须先在genvar中声明循环中使用的索引变量名,然后才能使用它。genvar声明的索引变量被用作整数用来判断generate循环。Verilog中generate循环中的generate块最好命名。通常,generate for循环和普通 for循环之间的主要区别在于generate for循环正在为每次迭代生成一个实例。例题Adder100i - HDLBits (01xz.net)代码module top_module(