1. MVP简介
M就是model,里边放的是javabean;
V就是View,就是Activity、Fragment;
P就是Presenter;
2. 自己使用
全局需要定义:
定义BaseView、BasePresenter,BaseView是View的父类,BasePresenter是Presenter的父类;
举例:这里以请求HomeFragment的 BannerView轮播图数据为例,结构如下:
由上图可以看出
1>:整个项目底部来回切换的多个fragment都是放在ui包下边的;
2>:自己手动新建一个contract包,定义HomeFragmentContract接口,在里边定义View继承BaseView,里边的方法用于给Activity或者Fragment回调;定义Presenter继承BasePresenter,里边的方法用于写具体的联网请求的逻辑代码,目的就是把具体联网请求的方法和给Activity、Fragment中提供的方法分开,达到最大程度解耦;
下边以home首页的fragment为例,定义4个包,分别是contract、model、view、presenter;
3. 具体分析
3.1:定义HomeFragmentContract接口,代码如下:
/**
* Email: 2185134304@qq.com
* Created by JackChen 2018/4/8 17:34
* Version 1.0
* Params:
* Description: :Home主页面
*/
public interface HomeFragmentContract {
//View(activity/fragment)继承,需要实现的方法
interface View extends BaseView {
//设置轮播图
void setBanner(BannerView mBanner, List<Object> arrayList);
void setOnclick(int position);
void setMarqueeClick(int position);
void setGridClick(int position);
void setGridClickThird(int position);
void setGridClickFour(int position);
void setNewsList2Click(int position, String url);
void setNewsList5Click(int position , String url);
}
//Presenter控制器
interface Presenter extends BasePresenter {
void setActivity(MainActivity activity);
//初始化
DelegateAdapter initRecyclerView(RecyclerView recyclerView);
BaseDelegateAdapter initBannerAdapter();
BaseDelegateAdapter initGvMenu();
BaseDelegateAdapter initMarqueeView();
BaseDelegateAdapter initTitle(String title);
BaseDelegateAdapter initList1();
BaseDelegateAdapter initList2();
}
}
contract中需要做的事:
1>:写一个 View接口用于继承BaseView,View就指的是Activity、Fragment,里边写的方法就是Activity或者Fragment中所需要实现的方法名字;
2>:写一个 Presenter接口继承BasePresenter控制器,里边的方法就是具体的联网请求的方法;
3.2:自己定义一个 HomeFragmentPresenter,只实现 HomeFrgmentContract.Presenter,然后复写所有的方法,而不实现HomeFragmentContract.View,目的是让Activity或者Fragment实现,这里就是让HomeFragment实现HomeFragmentContract.View,然后实现具体方法:
1>:HomeFrgmentContract中的View下边的方法,是让Activity、Fragment中回调的方法;
2>:HomeFragmentContract中的 Presenter下边的方法,是在HomeFragmentPresenter中实现的方法,然后把具体的联网请求的数据都写到Presenter下边的方法,只需要返回数据的结果给Activity或者Fragment就可以;
具体代码如下:
/**
* Email: 2185134304@qq.com
* Created by JackChen 2018/4/8 17:37
* Version 1.0
* Params:
* Description: HomeFragmentPresenter
*/
public class HomeFragmentPresenter implements HomeFragmentContract.Presenter {
private HomeFragmentContract.View mView;
private CompositeSubscription mSubscriptions;
private MainActivity activity;
public HomeFragmentPresenter(HomeFragmentContract.View androidView) {
this.mView = androidView;
mSubscriptions = new CompositeSubscription();
}
@Override
public void subscribe() {
}
@Override
public void unSubscribe() {
mSubscriptions.clear();
}
@Override
public void setActivity(MainActivity activity) {
this.activity = activity;
}
@Override
public DelegateAdapter initRecyclerView(RecyclerView recyclerView) {
//初始化
//创建VirtualLayoutManager对象
VirtualLayoutManager layoutManager = new VirtualLayoutManager(activity);
recyclerView.setLayoutManager(layoutManager);
//设置回收复用池大小,(如果一屏内相同类型的 View 个数比较多,需要设置一个合适的大小,防止来回滚动时重新创建 View)
RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
recyclerView.setRecycledViewPool(viewPool);
viewPool.setMaxRecycledViews(0, 20);
//设置适配器
DelegateAdapter delegateAdapter = new DelegateAdapter(layoutManager, true);
recyclerView.setAdapter(delegateAdapter);
return delegateAdapter;
}
/**
* 设置轮播图数据
* @return
*/
@Override
public BaseDelegateAdapter initBannerAdapter() {
final List<Object> arrayList = new ArrayList<>();
arrayList.add("http://bpic.wotucdn.com/11/66/23/55bOOOPIC3c_1024.jpg!/fw/780/quality/90/unsharp/true/compress/true/watermark/url/L2xvZ28ud2F0ZXIudjIucG5n/repeat/true");
arrayList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505470629546&di=194a9a92bfcb7754c5e4d19ff1515355&imgtype=0&src=http%3A%2F%2Fpics.jiancai.com%2Fimgextra%2Fimg01%2F656928666%2Fi1%2FT2_IffXdxaXXXXXXXX_%2521%2521656928666.jpg");
//banner
return new BaseDelegateAdapter(activity, new LinearLayoutHelper(), R.layout.view_vlayout_banner, 1, Constant.viewType.typeBanner) {
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
// 绑定数据
BannerView mBanner = holder.getView(R.id.banner);
mView.setBanner(mBanner,arrayList);
}
};
}
/**
* 设置8宫格数据
*/
@Override
public BaseDelegateAdapter initGvMenu() {
//menu
// 在构造函数设置每行的网格个数
final TypedArray proPic = activity.getResources().obtainTypedArray(R.array.find_gv_image);
final String[] proName = activity.getResources().getStringArray(R.array.find_gv_title);
final List<Integer> images = new ArrayList<>();
for(int a=0 ; a<proName.length ; a++){
images.add(proPic.getResourceId(a,R.mipmap.ic_data_picture));
}
proPic.recycle();
GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(4);
gridLayoutHelper.setPadding(0, 16, 0, 16);
gridLayoutHelper.setVGap(16); // 控制子元素之间的垂直间距
gridLayoutHelper.setHGap(0); // 控制子元素之间的水平间距
gridLayoutHelper.setBgColor(Color.WHITE);
return new BaseDelegateAdapter(activity, gridLayoutHelper, R.layout.item_vp_grid_iv, 8, Constant.viewType.typeGv) {
@Override
public void onBindViewHolder(BaseViewHolder holder, @SuppressLint("RecyclerView") final int position) {
super.onBindViewHolder(holder, position);
holder.setText(R.id.tv_new_seed_title, proName[position]);
holder.setImageResource(R.id.iv_new_seed_ic, images.get(position));
holder.getView(R.id.ll_new_seed_item).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mView.setOnclick(position);
}
});
}
};
}
/**
* 设置精选垂直滚动的数据
*/
@Override
public BaseDelegateAdapter initMarqueeView() {
LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();
return new BaseDelegateAdapter(activity,linearLayoutHelper , R.layout.view_vlayout_marquee, 1, Constant.viewType.typeMarquee) {
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
MarqueeView marqueeView = holder.getView(R.id.marqueeView);
List<String> info1 = new ArrayList<>();
info1.add("1.银卡惠,一款大家都在使用的产品,出售各种优惠劵!");
info1.add("2.欢迎入住银卡惠app,让您财运亨通!");
marqueeView.startWithList(info1);
// 在代码里设置自己的动画
marqueeView.setOnItemClickListener(new MarqueeView.OnItemClickListener() {
@Override
public void onItemClick(int position, TextView textView) {
mView.setMarqueeClick(position);
}
});
}
};
}
@Override
public BaseDelegateAdapter initTitle(final String title) {
return new BaseDelegateAdapter(activity, new LinearLayoutHelper(), R.layout.view_vlayout_title, 1, Constant.viewType.typeTitle) {
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
holder.setText(R.id.tv_title, title);
}
};
}
@Override
public BaseDelegateAdapter initList1() {
// //item1 gird
// final TypedArray list1_image = activity.getResources().obtainTypedArray(R.array.find_list1_image);
// final String[] list1_title = activity.getResources().getStringArray(R.array.find_list1_title);
// final List<Integer> images = new ArrayList<>();
// for(int a=0 ; a<list1_title.length ; a++){
// images.add(list1_image.getResourceId(a,R.mipmap.ic_data_picture));
// }
// list1_image.recycle();
// GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(4);
// gridLayoutHelper.setMargin(0, 0, 0, 0);
// gridLayoutHelper.setPadding(0, 20, 0, 10);
// gridLayoutHelper.setVGap(10);// 控制子元素之间的垂直间距
// gridLayoutHelper.setHGap(0);// 控制子元素之间的水平间距
// gridLayoutHelper.setWeights(new float[]{25, 25, 25 , 25});
// gridLayoutHelper.setBgColor(Color.WHITE);
// //gridLayoutHelper.setAutoExpand(true);//是否自动填充空白区域
// return new BaseDelegateAdapter(activity, gridLayoutHelper, R.layout.view_vlayout_grid, 8, Constant.viewType.typeGvSecond) {
// @Override
// public void onBindViewHolder(BaseViewHolder holder, @SuppressLint("RecyclerView") final int position) {
// super.onBindViewHolder(holder, position);
// holder.setText(R.id.tv_title, list1_title[position]);
// ImageView iv = holder.getView(R.id.iv_image);
// ImageUtils.loadImgByPicasso(activity, images.get(position), iv);
// holder.getItemView().setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// mView.setGridClick(position);
// }
// });
// }
// };
return null ;
}
@Override
public BaseDelegateAdapter initList2() {
LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();
linearLayoutHelper.setAspectRatio(4.0f);
linearLayoutHelper.setDividerHeight(5);
linearLayoutHelper.setMargin(0, 0, 0, 0);
linearLayoutHelper.setPadding(0, 0, 0, 10);
//linearLayoutHelper.setBgColor(0xFFF5A623);
return new BaseDelegateAdapter(activity, linearLayoutHelper, R.layout.item_tx_news_list, 3, Constant.viewType.typeNews) {
@Override
public void onBindViewHolder(BaseViewHolder holder, final int position) {
super.onBindViewHolder(holder, position);
if (Constant.findNews != null && Constant.findNews.size() > 0) {
HomeBlogEntity model = Constant.findNews.get(position);
holder.setText(R.id.tv_title, model.getTitle());
ImageView imageView = holder.getView(R.id.iv_logo);
ImageUtils.loadImgByPicassoError(activity, model.getImageUrl(), R.mipmap.image_default, imageView);
holder.setText(R.id.tv_time, model.getTime());
holder.getItemView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mView.setNewsList2Click(position,Constant.findNews.get(position).getUrl());
}
});
} else {
ImageView imageView = holder.getView(R.id.iv_logo);
holder.setText(R.id.tv_title, "标题 ");
imageView.setImageResource(R.mipmap.image_default);
holder.setText(R.id.tv_time, "时间");
}
}
};
}
/**
* 豆瓣电影
*/
@Override
public BaseDelegateAdapter initList3() {
final TypedArray list3_image = activity.getResources().obtainTypedArray(R.array.find_list3_image);
final String[] list3_title = activity.getResources().getStringArray(R.array.find_list3_title);
final String[] list3_title_price = activity.getResources().getStringArray(R.array.find_list3_title_price);
final List<Integer> images = new ArrayList<>();
for(int a=0 ; a<list3_title.length ; a++){
images.add(list3_image.getResourceId(a,R.mipmap.ic_data_picture));
}
list3_image.recycle();
GridLayoutHelper gridLayoutHelper = new GridLayoutHelper(3);
gridLayoutHelper.setMargin(20, 0, 20, 0);
gridLayoutHelper.setPadding(0, 20, 0, 10);
gridLayoutHelper.setBgColor(Color.WHITE);
//gridLayoutHelper.setAspectRatio(1.5f); // 设置设置布局内每行布局的宽与高的比
// gridLayoutHelper特有属性(下面会详细说明)
//设置每行中 每个网格宽度 占 每行总宽度 的比例
gridLayoutHelper.setWeights(new float[]{30, 40, 30});
gridLayoutHelper.setVGap(0);// 控制子元素之间的垂直间距
gridLayoutHelper.setHGap(5);// 控制子元素之间的水平间距
//gridLayoutHelper.setAutoExpand(false);//是否自动填充空白区域
//gridLayoutHelper.setSpanCount(6); // 设置每行多少个网格
return new BaseDelegateAdapter(activity, gridLayoutHelper, R.layout.view_vlayout_hor, 3, Constant.viewType.typeList) {
@Override
public void onBindViewHolder(BaseViewHolder holder, @SuppressLint("RecyclerView") final int position) {
super.onBindViewHolder(holder, position);
holder.setText(R.id.tv_title, list3_title[position]);
holder.setText(R.id.tv_price , list3_title_price[position]) ;
ImageView iv = holder.getView(R.id.iv_image);
ImageUtils.loadImgByPicasso(activity, images.get(position), iv);
holder.getItemView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 豆瓣的3个图片的点击事件
mView.setGridClickThird(position);
}
});
}
};
// return null ;
}
/**
* 为您精选
*/
@Override
public BaseDelegateAdapter initList4() {
final TypedArray list4_image = activity.getResources().obtainTypedArray(R.array.find_list4_image);
final String[] list4_title = activity.getResources().getStringArray(R.array.find_list4_title);
final String[] list4_title_price = activity.getResources().getStringArray(R.array.find_list4_title_price);
final List<Integer> images = new ArrayList<>();
for(int a=0 ; a<list4_title.length ; a++){
images.add(list4_image.getResourceId(a,R.mipmap.ic_data_picture));
}
list4_image.recycle();
OnePlusNLayoutHelper onePlusNLayoutHelper = new OnePlusNLayoutHelper();
//noinspection deprecation
onePlusNLayoutHelper.setBgColor(activity.getResources().getColor(R.color.colorWhite));
//onePlusNLayoutHelper.setAspectRatio(2.0f);
//onePlusNLayoutHelper.setColWeights(new float[]{40f});
//onePlusNLayoutHelper.setRowWeight(30f);
onePlusNLayoutHelper.setMargin(0, 0, 0, 0);
onePlusNLayoutHelper.setPadding(10, 20, 10, 10);
return new BaseDelegateAdapter(activity, onePlusNLayoutHelper, R.layout.view_vlayout_plus, 3, Constant.viewType.typePlus) {
@Override
public void onBindViewHolder(BaseViewHolder holder, @SuppressLint("RecyclerView") final int position) {
super.onBindViewHolder(holder, position);
if (position == 0) {
holder.getView(R.id.ll_first).setVisibility(View.VISIBLE);
holder.getView(R.id.ll_second).setVisibility(View.GONE);
holder.setText(R.id.tv_title, list4_title[position]);
holder.setText(R.id.tv_price, list4_title_price[position]);
holder.setImageResource(R.id.iv_image, images.get(position));
} else {
holder.getView(R.id.ll_first).setVisibility(View.GONE);
holder.getView(R.id.ll_second).setVisibility(View.VISIBLE);
holder.setText(R.id.tv_title2, list4_title[position]);
holder.setText(R.id.tv_price_2, list4_title_price[position]);
holder.setImageResource(R.id.iv_image2, images.get(position));
}
holder.getItemView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mView.setGridClickFour(position);
}
});
}
};
}
/**
* 优质新闻
*/
@Override
public BaseDelegateAdapter initList5() {
LinearLayoutHelper linearLayoutHelper = new LinearLayoutHelper();
linearLayoutHelper.setAspectRatio(4.0f);
linearLayoutHelper.setDividerHeight(5);
linearLayoutHelper.setMargin(0, 0, 0, 0);
linearLayoutHelper.setPadding(0, 0, 0, 10);
// 参数3:布局文件 参数4:一页显示的个数 参数5:int typeFooter = 9 //底部
return new BaseDelegateAdapter(activity, linearLayoutHelper, R.layout.view_vlayout_news, 10, Constant.viewType.typeFooter) {
@Override
public void onBindViewHolder(BaseViewHolder holder, final int position) {
super.onBindViewHolder(holder, position);
// 如果底部新闻请求的数据大于0,就执行if;否则执行else
if (Constant.findBottomNews != null && Constant.findBottomNews.size() > 0) {
Log.e("TAG" , "if语句") ;
// HomeBlogEntity model = Constant.findBottomNews.get(position);
// holder.setText(R.id.tv_title, model.getTitle());
// ImageView imageView = holder.getView(R.id.iv_logo);
// ImageUtils.loadImgByPicassoError(activity, model.getImageUrl(), R.mipmap.image_default, imageView);
// holder.setText(R.id.tv_time, model.getTime());
// holder.getItemView().setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// mView.setNewsList5Click(position,Constant.findBottomNews.get(position).getUrl());
// }
// });
} else {
// Log.e("TAG" , "else语句") ;
ImageView imageView = holder.getView(R.id.iv_logo);
holder.setText(R.id.tv_title, "官方自营IPhone9 Plus ");
imageView.setImageResource(R.mipmap.test_iphone);
holder.setText(R.id.tv_time, "¥129999");
holder.getItemView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { // Constant.findBottomNews.get(position).getUrl()
mView.setNewsList5Click(position,"");
}
});
}
}
};
}
}
3.3:model:用于存放BannerView轮播图的javabean数据;
3.4:view:定义fragment包,创建HomeFragment然后实现HomeFragmentContract.View,然后实现里边的方法;
1>:直接在HomeFragment中创建presenter对象,然后调用HomeFragmentPresenter中对应的方法来获取返回的数据,从而就可以在HomeFragment中利用返回的数据来填充BannerView页面的数据和其他控件的数据;
代码如下:
/**
* Email: 2185134304@qq.com
* Created by JackChen 2018/4/9 10:06
* Version 1.0
* Params:
* Description:
*/
public class HomeFragment extends BaseFragment implements View.OnClickListener , HomeFragmentContract.View {
private MainActivity activity;
private HomeFragmentContract.Presenter presenter = new HomeFragmentPresenter(this);
@Bind(R.id.tv_title)
TextView tvTitle;
@Bind(R.id.recyclerView)
RecyclerView recyclerView;
/** 存放各个模块的适配器*/
private List<DelegateAdapter.Adapter> mAdapters;
private BannerView mBanner;
// private Realm realm;
private static boolean isFirstEnter = true;
private RefreshLayout refreshLayout;
private Intent intent;
@Override
public void onAttach(Context context) {
super.onAttach(context);
activity = (MainActivity) context;
}
@Override
public void onDetach() {
super.onDetach();
if(activity!=null){
activity = null;
}
}
@Override
public void onPause() {
super.onPause();
if(mBanner!=null){
mBanner.pause();
}
}
@Override
public void onResume() {
super.onResume();
if(mBanner!=null){
mBanner.resume();
}
}
@Override
public void onDestroy() {
super.onDestroy();
restore();
presenter.unSubscribe();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter.subscribe();
}
@Override
public void onClick(View v) {
}
@Override
public int getContentView() {
install();
return R.layout.fragment_example_assign_default; // base_recycler_view
}
@Override
public void initView() {
refreshLayout = (RefreshLayout) activity.findViewById(R.id.refreshLayout);
mAdapters = new LinkedList<>();
// initRealm();
presenter.setActivity(activity);
initRecyclerView();
tvTitle.setText("首页");
// activity.showToolBar();
}
private void initRecyclerView() {
}
/**
* 设置轮播图数据
*/
@Override
public void setBanner(BannerView mBanner, List<Object> arrayList) {
this.mBanner = mBanner;
mBanner.setHintGravity(2);
mBanner.setAnimationDuration(1000);
mBanner.setPlayDelay(2000);
mBanner.setHintPadding(0,0,0, SizeUtil.dip2px(activity,10));
mBanner.setAdapter(new BaseBannerPagerAdapter(activity, arrayList));
}
@Override
public void initListener() {
}
@Override
public void initData() {
}
@Override
public void setOnclick(int position) {
}
@Override
public void setMarqueeClick(int position) {
}
@Override
public void setGridClick(int position) {
}
@Override
public void setGridClickThird(int position) {
}
}
/**
* 为您精选
*/
@Override
public void setGridClickFour(int position) {
}
}
@Override
public void setNewsList2Click(int position, String url) {
}
}
}
4. 总结
上边啰啰嗦嗦这么多,大家如果不是很清楚或者不是很理解的,也没有关系,可以不用看上边的,只需要把我下边的总结看懂就ok,照样也可以很好的把MVP用在项目中。
1>:整个项目涉及到Activity或者Fragment包是ui包,然后在ui包下边创建底部所有的fragment包,如home、cart、my,表示首页、购物车、我的;
2>:全局创建BaseView、BasePresenter;
3>:然后针对于home首页,在里边创建4个包,分别是contract、model、view、presenter;
对于contract,创建HomeFragmentContract接口,需要做两件事:
第一:定义View接口,继承BaseView,然后定义一些方法,View下的方法作用是给Activity或者Fragment回调的;
第二:定义Presenter接口,继承BasePresenter,然后定义一些方法,Presenter下的方法作用是写具体进行联网请求的代码,来获取网络返回的数据;
4>:定义HomeFragmentPresenter,实现HomeFragmentContract.Presenter,然后实现里边的方法,把每一个需要填充数据的控件,所需要调用的接口的联网请求都写到对应的方法中,然后调用V层的回调方法,用于返回数据给Activity或者Fragment;
5>:让HomeFragment实现 HomeFragmentContract.View,然后实现里边的方法,即就是V层中的方法,V层中的方法其实在P层中已经获取到了数据,这里只是通过回调接口把数据回传给Activity或者Fragment的即可,然后在HomeFragment中直接获取到数据后,就可以给所需要的控件去填充数据就ok;
5. 注意:
上边自己只是举了一个具体的应用场景,我要说的是其他的所有页面,不管是其他的Fragment或者是点击任何一个Fragment中的按钮或者点击任何地方的按钮进入某个Activity,都是可以使用上边的方式来处理数据,也就是说每一个小模块都需要创建对应4个包,分别是contract、model、view、presenter,然后在对应的包下创建对应的类,然后做对应的事情就ok。
以上就是自己在项目中MVP具体的使用方法,如果还不是特别清楚的,可以给我发私信,或者加我qq都是可以的