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

转载地址:http://blog.csdn.net/u014315849/article/details/51385333




最近更新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这种情况进行划分组织目录。 
google官方MVP架构目录视图 
2 具体实现流程

我们将关注度放到具体的一个taskdetail模块当中来解析实现MVP的流程。 
taskdetail模块 
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层的交互。 

通过上面的分析,在来梳理一下整个步骤: 
官方MVP实例,通过协议类XXXContract来对View和Presenter的接口进行内部继承。是对BaseView和BasePresenter的进一步封装,所以我们实现的View和Presenter也只需要继承XXXContract中的对应内部接口就行。

**2 **activity的作用主要是创建View(这里是相应的fragment),以及创建presenter,并把view传递给presenter

在presenter的实现类的构造函数中,通过view的setPresenter,让view获得了presenter实例。这样view中就可以对Presenter中的方法进行操作了。

在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);

}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

3.2 BasePresenter 
只有一个start方法。将在view界面初始化后调用(onResume方法中)

public interface BasePresenter {   
 void start();
}
   
   
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

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();
    }


}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

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!");
    }
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210

这里也实现了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() {
    }
}

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

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;
        }
    }
}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

具体请参看本篇文章项目github地址:MVPCommon

4 参考资料:

Android官方MVP架构示例项目解析 
AndroidArchitectureCollection


最近更新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这种情况进行划分组织目录。 
google官方MVP架构目录视图 
2 具体实现流程

我们将关注度放到具体的一个taskdetail模块当中来解析实现MVP的流程。 
taskdetail模块 
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层的交互。 

通过上面的分析,在来梳理一下整个步骤: 
官方MVP实例,通过协议类XXXContract来对View和Presenter的接口进行内部继承。是对BaseView和BasePresenter的进一步封装,所以我们实现的View和Presenter也只需要继承XXXContract中的对应内部接口就行。

**2 **activity的作用主要是创建View(这里是相应的fragment),以及创建presenter,并把view传递给presenter

在presenter的实现类的构造函数中,通过view的setPresenter,让view获得了presenter实例。这样view中就可以对Presenter中的方法进行操作了。

在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);

}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

3.2 BasePresenter 
只有一个start方法。将在view界面初始化后调用(onResume方法中)

public interface BasePresenter {   
 void start();
}
    
    
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

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();
    }


}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

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!");
    }
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210

这里也实现了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() {
    }
}

    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

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;
        }
    }
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

具体请参看本篇文章项目github地址:MVPCommon

4 参考资料:

Android官方MVP架构示例项目解析 
AndroidArchitectureCollection

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值