您的位置:首页 > 运维架构 > 网站架构

google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))

2016-05-12 16:45 736 查看
最近更新2016.5.10(已经添加整个项目目录。更新新闻资讯)

本篇文章项目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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: