google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
来源:互联网 发布:android网络状态监听 编辑:程序博客网 时间:2024/05/21 06:26
本篇文章项目github地址:MVPCommon
本文章原地址:简书博客
1 前言
当然对于MVP的解说也是使用也是层出不穷,我也网络上也能看到各种版本的解说,之前博客也有文章的更新,里面有MVP的详细说明和项目代码--->Android中的MVP模式,带实例。
本篇文章将参考 google官方android MVP架构项目的实现,来实现自己的项目。或许看了这篇文章之后,你再去梳理一下google官方架构项目,会让你收获更多。官方的实例肯定具有更好的权威性。
推荐关注安卓各种架构相关文章合集github地址:AndroidArchitectureCollection
2 google官方MVP架构解析
1 项目目录
打开github,展开项目目录,会发现项目结构的组织方式是按照功能进行分模块的,当然根据个人情况,也可以按照ui,model,view,presenter这种情况进行划分组织目录。
2 具体实现流程
我们将关注度放到具体的一个taskdetail模块当中来解析实现MVP的流程。
2.1 TaskDetailContract
可以看到这里是通过一个协议类XXXContract来对View和Presenter的接口进行继承。这样做的好处也就是,我们可以将基础的View层的操作放在BaseView里面,对基础的Presenter层的操作放在BasePresenter里面。减少后续代码的重复。一个协议类也将View和Presenter管理起来,方便操作。
2.2 BaseView
那么来看看BaseView,主要是有一个setPresenter的操作,MVP中Presenter和View层是需要交互的,这里通过setPresenter操作,我们也就可以获得Presenter层的实例进行交互了。所以在我们自己的代码中,我们也可以将加载的loading,以及加载错误页面,加载失败页面等操作放在BaseView里面,这是每个View都会有的:
2.3 BasePresenter
BasePresenter中只有一个start方法,表示“开始”,我们可以在这里进行数据加载初始化等。
2.3 TaskDetailActivity
可以看到这里这里一个初始化了fragment的activity,主要操作当让是new了一个XXXPresenter。activity在项目中是一个全局的控制者,负责创建view以及presenter实例,并将二者联系起来,
2.4 TaskDetailFragment
Fragment是MVP中View的实现类,它不与Model 层进行交互,只和presenter的实例进行交互。
2.5 TaskDetailPresenter
Presenter的真正实现类,在这里进行model层和view层的交互。
通过上面的分析,在来梳理一下整个步骤:
1 官方MVP实例,通过协议类XXXContract来对View和Presenter的接口进行内部继承。是对BaseView和BasePresenter的进一步封装,所以我们实现的View和Presenter也只需要继承XXXContract中的对应内部接口就行。
2 activity的作用主要是创建View(这里是相应的fragment),以及创建presenter,并把view传递给presenter
3 在presenter的实现类的构造函数中,通过view的setPresenter,让view获得了presenter实例。这样view中就可以对Presenter中的方法进行操作了。
4 在presenter的实现类中,可以对Model数据进行操作。实例中,数据的获取、存储、数据状态变化都是model层的任务,presenter会根据需要调用该层的数据处理逻辑并在需要时将回调传入。这样model、presenter、view都只处理各自的任务,此种实现确实是单一职责最好的诠释。
3 实战应用:
说了这么多,通过一个主页面的搭建,来完整的使用MVP吧。
3.1 BaseView
我在这里没有添加setPresenter方法,而是将loading,以及加载错误,网络加载错误等页面都放在了这里面。
public interface BaseView {// void setPresenter(P presenter); void showLoading(String msg); void hideLoading(); void showError(String msg, View.OnClickListener onClickListener); void showEmpty(String msg, View.OnClickListener onClickListener); void showEmpty(String msg, View.OnClickListener onClickListener, int imageId); void showNetError(View.OnClickListener onClickListener);}
3.2 BasePresenter
只有一个start方法。将在view界面初始化后调用(onResume方法中)
public interface BasePresenter { void start();}
3.3 DrawerMainContract
可以看到相比官方的实例我在其中添加了一个onGetDrawerListListener,主要是用于获取model层数据之后,进行数据的监听。
public interface DrawerMainContract { interface Presenter extends BasePresenter{//获取数据 void getDrawerList();//头像点击 void onDrawerIconClicked();//获取fragment void getSelectFragment(int position); } interface View extends BaseView{//获取数据后,更新界面 void onDrawerListGet(ArrayList<DrawerItemsData.DrawerItem> list);//设置头像 void setDrawerIcon(int resId);//fragment返回后 void onSelectFragmentGet(Fragment fragment); }//数据监听 interface onGetDrawerListListener { void onSuccess(); void onError(); }}
3.4 DrawerMainActivity
在开发中Fragment,Activity以及自定义view都可以作为MVP中View的实现。这里也在创建presenter实例的时候传入了当前view。并调用了 mPresenter.getDrawerList()进行获取数据,mPresenter.getSelectFragment(0);设置当前为第一个fragment。
/** * Created by Anthony on 2016/5/3. * Class Note: * 1 use{@link DrawerLayout} to * acts as a top-level container for window content that allows for * interactive "drawer" views to be pulled out from the edge of the window. * 2 View in MVP * see {@link DrawerMainContract}------Manager role of MVP * {@link DrawerMainPresenter}---------Presenter * &{@link DrawerMainActivity}---------View * &{@link DrawerItemsData}------------Model */public class DrawerMainActivity extends AbsBaseActivity implements DrawerMainContract.View, View.OnClickListener { private Toolbar actionBarToolbar; public static DrawerLayout drawerLayout; private ListView mDrawerMenu; private CircleImageView mUserImg; private NavDrawerListAdapter mAdapter; private DrawerMainPresenter mPresenter; @Override protected int getContentViewID() { return R.layout.activity_drawer; } @Override protected void onResume() { super.onResume(); mPresenter.start(); } @Override protected void initViewsAndEvents() { super.initViewsAndEvents();//一定要调用super,进行父类中的一些初始化操作 initDrawerLayout(); setupToolBar(); //hide toolBar ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.hide(); } mUserImg = (CircleImageView) findViewById(R.id.user_img); mUserImg.setOnClickListener(this); mDrawerMenu = (ListView) findViewById(R.id.left_menu);// mPresenter = new DrawerMainPresenter(this, mContext); //create and initialize presenter, mPresenter= new DrawerMainPresenter(this,mContext); //use presenter to load data mPresenter.getDrawerList(); //default select first fragment mPresenter.getSelectFragment(0); } protected void initDrawerLayout() { drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); if (drawerLayout == null) { // current activity does not have a drawer. return; } if (getDrawerLayoutId() != 0) { FrameLayout leftLayout = (FrameLayout) findViewById(R.id.left_drawer_layout); View nav_drawer_layout = getLayoutInflater().inflate(getDrawerLayoutId(), null); leftLayout.addView(nav_drawer_layout); } } protected void setupToolBar() { if (actionBarToolbar == null) { actionBarToolbar = (Toolbar) findViewById(R.id.toolbar); if (actionBarToolbar != null) { setSupportActionBar(actionBarToolbar); } } final ActionBar ab = getSupportActionBar(); if (ab == null) return; ab.setHomeAsUpIndicator(R.drawable.ic_menu); ab.setDisplayHomeAsUpEnabled(true); } public static void openDrawer() { if (drawerLayout == null) return; drawerLayout.openDrawer(GravityCompat.START); } public static void closeDrawer() { if (drawerLayout == null) return; drawerLayout.closeDrawer(GravityCompat.START); } /** * close drawer if drawer is opening */ @Override public void onBackPressed() { if (drawerLayout.isDrawerOpen(GravityCompat.START)) { closeDrawer(); } else { super.onBackPressed(); } } protected int getDrawerLayoutId() { return R.layout.nav_drawer_layout; } @Override public void onClick(View v) { if (v.getId() == R.id.user_img) { mPresenter.onDrawerIconClicked(); } } @Override public void onDrawerListGet(final ArrayList<DrawerItemsData.DrawerItem> mDrawerItems) { mAdapter = new NavDrawerListAdapter(this, mDrawerItems); mDrawerMenu.setAdapter(mAdapter); mDrawerMenu.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { if (!BaseUtil.isEmpty(mDrawerItems, i)) { DrawerItemsData.DrawerItem drawerItem = mDrawerItems.get(i); if (drawerItem != null) { mPresenter.getSelectFragment(i); } } } }); } @Override public void setDrawerIcon(int resId) { mUserImg.setImageResource(resId); } @Override public void onSelectFragmentGet(Fragment fragment) { closeDrawer(); FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.content, fragment).commit(); } @Override protected void onNetworkConnected(NetUtils.NetType type) { ToastUtils.getInstance().showToast("this type is"+type); } @Override protected void onNetworkDisConnected() { ToastUtils.getInstance().showToast("no network disconnected"); } @Override protected View getLoadingTargetView() { return null; }// @Override// public void setPresenter(DrawerMainContract.Presenter presenter) {// mPresenter= (DrawerMainPresenter) presenter;// } @Override public void showLoading(String msg) { toggleShowLoading(true, msg); } @Override public void hideLoading() { toggleShowLoading(false, ""); } @Override public void showError(String msg, View.OnClickListener onClickListener) { } @Override public void showEmpty(String msg, View.OnClickListener onClickListener) { toggleShowEmpty(true, msg, onClickListener); } @Override public void showEmpty(String msg, View.OnClickListener onClickListener, int imageId) { toggleShowEmpty(true, msg, onClickListener, imageId); } @Override public void showNetError(View.OnClickListener onClickListener) { ToastUtils.getInstance().showToast("oops ,no network now!"); }}
这里也实现了DrawerMainContract.View以及BaseView中的所有方法。
3.5 DrawerMainPresenter
对DrawerMainContract.Presenter和DrawerMainContract.
onGetDrawerListListener的实现。
可以看到DrawerItemsData就是model层的对象。主要封装的是本地的字符串和图片数据。
/** * Created by Anthony on 2016/5/3. * Class Note: Presenter in MVP * see {@link DrawerMainContract}--------Manager role of MVP * &{@link DrawerMainPresenter}------Presenter * &{@link DrawerMainActivity}-------------View * &{@link DrawerItemsData}-----------Model */public class DrawerMainPresenter implements DrawerMainContract.Presenter, DrawerMainContract.onGetDrawerListListener { private DrawerMainContract.View mView; private Context mContext; private DrawerItemsData mData; public DrawerMainPresenter(DrawerMainContract.View mView, Context mContext) { this.mContext = mContext; this.mView = mView;// mView.setPresenter(this);//bind presenter for View mData = new DrawerItemsData(mContext, this);//bind data listener for Model } @Override public void onDrawerIconClicked() { //已经登录,跳到个人详情页 ToastUtils.getInstance().showToast("icon clicked"); //没有登录 ,则跳到登录页面。。。 } @Override public void getDrawerList() { mData.initItemsData(); } @Override public void getSelectFragment(int position) { if (position == 3) mView.onSelectFragmentGet(new NewsChannelFragment()); else mView.onSelectFragmentGet(new TestFragment()); } @Override public void onSuccess() { mView.onDrawerListGet(mData.mDrawerItems); mView.setDrawerIcon(R.drawable.icon_head); } @Override public void onError() { // show error view mView.showNetError(new View.OnClickListener() { @Override public void onClick(View v) { } }); } @Override public void start() { }}
3.6 DrawerItemsData
这就是我主页面的model层的数据,当然后面可能会对这些数据进行修改,或者添加上网络访问。但是你会发现再也不用像以前那样要去修改整个activity了,只需要的是修改这个类。这也是MVP的作用,单一职责。
/** * Created by Anthony on 2016/5/3. * Class Note: * drawer list item data. * */public class DrawerItemsData { private Context mContext; public ArrayList<DrawerItem> mDrawerItems; private String[] mMenuTitles; private TypedArray mMenuIconsTypeArray; private TypedArray mMenuIconTintTypeArray; private DrawerMainContract.onGetDrawerListListener mListener; public DrawerItemsData(Context context, DrawerMainContract.onGetDrawerListListener listener) { this.mContext = context; this.mListener =listener; mDrawerItems=new ArrayList<>(); } public void initItemsData() { mMenuTitles = mContext.getResources().getStringArray(R.array.nav_drawer_items); // nav drawer icons from resources mMenuIconsTypeArray = mContext.getResources() .obtainTypedArray(R.array.nav_drawer_icons); mMenuIconTintTypeArray = mContext.getResources() .obtainTypedArray(R.array.nav_drawer_tint); for (int i = 0; i < mMenuTitles.length; i++) { mDrawerItems.add(new DrawerItem(mMenuTitles[i], mMenuIconsTypeArray .getResourceId(i, -1), mMenuIconTintTypeArray.getResourceId(i, -1))); } mMenuIconsTypeArray.recycle(); if(mDrawerItems.size()==mMenuTitles.length){ mListener.onSuccess(); }else{ mListener.onError(); } } public class DrawerItem { private String title; private int icon; //图片颜色 private int tint; private String count = "0"; // boolean to set visiblity of the counter private boolean isCounterVisible = false; public DrawerItem(){} public DrawerItem(String title, int icon, int tint){ this.title = title; this.icon = icon; this.tint = tint; } public DrawerItem(String title, int icon, boolean isCounterVisible, String count){ this.title = title; this.icon = icon; this.isCounterVisible = isCounterVisible; this.count = count; } public String getTitle(){ return this.title; } public int getIcon(){ return this.icon; } public String getCount(){ return this.count; } public boolean getCounterVisibility(){ return this.isCounterVisible; } public void setTitle(String title){ this.title = title; } public void setIcon(int icon){ this.icon = icon; } public void setCount(String count){ this.count = count; } public int getTint() { return tint; } public void setTint(int tint) { this.tint = tint; } public void setCounterVisibility(boolean isCounterVisible){ this.isCounterVisible = isCounterVisible; } }}
具体请参看本篇文章项目github地址:MVPCommon
4 参考资料:
Android官方MVP架构示例项目解析
AndroidArchitectureCollection
原文链接:http://www.jianshu.com/p/569ab68da482
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
- google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
- google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
- google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
- google官方架构MVP解析与实战【从零开始搭建android框架系列(3)】
- Google官方MVP+Dagger2架构详解【从零开始搭建android框架系列(6)】
- Google官方架构MVP解析与实战
- 浅析MVP中model层设计【从零开始搭建android框架系列(7)】
- android 从零开始搭建框架系列(1)
- android 从零开始搭建框架系列(2)
- Google 官方Android MVP架构实践
- 基于Android真实项目教你一步一步搭建架构2 -- Google官方Mvp架构
- Android MVP开发模式 google 官方Mvp架构详解
- Android官方MVP架构示例项目解析
- Android官方MVP架构示例项目解析
- Android官方MVP架构示例项目解析
- Android官方MVP架构示例项目解析
- Android官方MVP架构示例项目解析
- Android官方MVP架构示例项目解析
- POJ 2081 Recaman's Sequence
- 趣学 C 语言(二)—— typedef 与 #define
- 网络编程之TCP/UDP及其流程比较
- Android性能优化之Java代码优化
- Codeforces 643C Levels and Regions(斜率优化dp)
- google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
- 字典序最小问题
- (OK) use—install—IMUNES—commands
- VMwareWorkstation12注册机、您无权输入许可证密钥,请请使用系统管理员账户重试
- Java学习·web学习_选择器
- iOS 延迟执行的几种方式 —— HERO博客
- 构造MaxTree
- sql随机查询数据
- CSS预处理器