Android 之MVP模式

本文详细介绍MVP模式在Android开发中的应用,包括架构设计、代码实现及最佳实践。通过实例讲解如何利用RxJava、Retrofit等技术搭建高效解耦的MVP架构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:如果童鞋对于接口回调,多态,泛型(这个很重要)不是特别熟练,或者不是特别了解,建议还是不要使用这种模式。先谢谢常规MVP练练手,等真正对这些知识能熟练掌握了再来学习MVP模式。这个架构用到了大量的接口,泛型。(基础很重要啊)

使用MVP模式架构项目也有2个了。最新的项目原本想结合Dagger2去做(听说会让结构更加清晰)。不过在看了一上午Dagger2以后,我决定下个项目再集成,先把现有的MVP模式自己封装好。
先说下项目使用技术 RxJava+Retrofit+Gson+butterknife SDK:25 开发环境Studio
如果没有听说过以上技术,自行百度,这些在16年就比较流行了。

首先Gradle配置下

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.1.0'
    testCompile 'junit:junit:4.12'
    //网络解析
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
    compile 'com.squareup.okhttp3:okhttp:3.2.0'
    //RxJava相关
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'io.reactivex:rxandroid:1.1.0'
    //控制台输出管理 这个东西是github项目,如果使用需要在Project的gradle下添加下远程仓库的支持 代码如下
    compile 'com.github.blindmonk:Library:1.0.3'
    //作者自己的jar包,是用于处理沉浸式状态栏的,没有混淆,随便用
    compile files('libs/translucent_bars.jar')
    //注解框架
    compile 'com.jakewharton:butterknife:7.0.0'

如果想添加控制台输出依赖 ,在Progect的gradle下添加如下代码(主要为了解决 原生Log输出字符数限制)

allprojects {
    repositories {
        jcenter()
        //控制台无限制输出 远程仓库
        maven { url "https://jitpack.io" }
    }
}

基本配置完成,说说MVP模式:
传统的MVC模式,Activity同时担任了View的职责和Controller的职责。整个类过于臃肿,一个8000行的类,让你去维护,有没有砸电脑的心情。
而MVP模式,高度解耦,使得Activity和Fragment只负责View层。
P对应的是Presenter

去年,我所遇到的关于MVP的Demo,接口过于臃肿,并且BaseActivity和BaseFragment封装的不是太好,用到具体Presenter的时候总是伴随着强转,并且需要定义的接口类太多(我相信有过那段体验的童鞋会跟我有同感,我们是外包哎,公司可不管理代码质量怎么样,只要功能有了,程序不闪退就行,也不会因为你代码质量提升了就给我多的项目时间,吐槽下。)

首先,一个好的项目,应当有一个清晰可见的命名规范,否则维护起来,难度大大增加。说说我自己的项目规范吧(万一成为行业规范那?嘿嘿)
在项目 视图包下(个人习惯取名ui )下新建mvp包,mvp包分别有三个子包:iml,interfaces,presenter。

先说说分别是干啥的吧。
iml用于存放各种交互,通常为网络请求。
interfaces用于存放IBaseView以及其子类 这个IBaseView是干嘛的? 就是一个接口,所有的Activity都要实现它或者它的子类。里面封装了各种回调,比如获取到网络数据了,你要有一个对象回调到Activity中去做显示,此时,就需要IBaseView了,本质就是接口。是链接module和view的一个桥梁
presenter:里面存放所有presenter。这个Presenter是干嘛的?就是Activity大部分逻辑处理,为什么说不是全部?因为有的是处理不了的,就比如onActivityResult 里面处理的,就放在Activity中比较合理,放到Presenter就显得不是很合理。

首先定义基类 基类有三个,分别是BasePresenter IBaseView IViewBase
先简单介绍一下:
BasePresenter:所有的Presenter的基类,里面封装了一些通用的东西,如Presenter与Activity绑定,解绑,IBaseView对象的获取等等。可拓展。
IBaseView:是一个接口,主要用于每个Activity的回调处理,其子类也是改接口,需要手动实现。
IViewBase:是一个接口,挂载Presenter 等方法

下面分别贴出代码

BasePresenter

public abstract class BasePresenter<T extends IBaseView> {
    public T mView;//这个是要回调的接口的对象
    public Context mContext;
    protected String token="token";
    public void attach(T mView) {
        this.mView = mView;
    }

    public void detachView() {
        if (mView != null) {
            mView = null;
        }
    }




}

IBaseView:空接口,用于封装使用

public interface IBaseView {
}

IViewBase: 抽取一些方法,用于在BaseActivity和BaseFragment里去实现

public interface IViewBase<K extends IBaseView,T extends BasePresenter<K>> {
    T getPresenter();//Presenter对象
    int getLayoutId();//布局id
    View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);//创建View

    void bindView(Bundle savedInstanceState);//onCreate()执行

    View getView();//获取根View

}

下面贴出BaseActivity:

public abstract class BaseActivity<K extends IBaseView,T extends BasePresenter<K>>  extends AppCompatActivity implements IViewBase<K,T> ,IBaseView{
    /**
     * 根文件
     */
    protected View rootView;

    public T mPresenter;

    protected MyTitleBarView mTitleBarView;

    protected Context context;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context=this;
        init(savedInstanceState);
    }


    private void init(Bundle savedInstanceState) {
        //状态栏设置  true:是否开启 小米和魅族 状态栏字体颜色变色  true:开启 false:不开启 这个是作者的一个jar的代码,用于实现沉浸式状态栏,集成的时候删掉此代码就行,我也会把这个jar上传上去。
        StatusUtils.builder(this,R.color.main_color,true);

        //初始化RootView
        rootView=createView(null,null,savedInstanceState);
        //设置布局
        setContentView(rootView);



        mTitleBarView= (MyTitleBarView) findViewById(R.id.title_bar);

        mPresenter=getPresenter();

        if (mPresenter != null) {
            mPresenter.attach((K) this);
            mPresenter.mContext=this;
        }
        bindView(savedInstanceState);

        AppManager.getAppManager().addActivity(this);

        getIntentDate(getIntent());

    }

    @Override
    public View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view=LayoutInflater.from(this).inflate(getLayoutId(),null);
        //项目集成 ButterKnife  如果没用到这个注解插件,注释此行代码,用findViewById就行
        ButterKnife.bind(this, view);
        return view;
    }

    protected void back() {
        finish();
    }


    //获取页面传递数据
    protected  void getIntentDate(Intent intent) {

    }



    @Override
    protected void onDestroy() {
        super.onDestroy();
        //作者自己的Activity管理类,注释就行,如有兴趣,会上传项目代码,里面都有
        AppManager.getAppManager().removeActivity(this);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            back();
        }

        return false;
    }



    @Override
    public View getView() {
        return rootView;
    }

上传一个示例Activity:MainActivityCallView 是一个接口,所有的页面回调工作由他完成 集成自IBaseView 接口
MainActivityPresenter 具体的Presenter

public class MainActivity extends BaseActivity<MainActivityCallView,MainActivityPresenter> implements MainActivityCallView{

    @Override
    public MainActivityPresenter getPresenter() {
        return new MainActivityPresenter();
    }

    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    public void bindView(Bundle savedInstanceState) {
        mPresenter.login();
    }



    //控制台输出下结果
    @Override
    public void loginSuccess() {
        LogUtils.i("回调成功");
    }
}

MainActivityCallView:是一个接口 里面有所有Presenter需要回调到Activity层展示的方法

public interface MainActivityCallView extends IBaseView {
    void loginSuccess();
}

MainActivityPresenter:IML_MainAService 是网络交互的接口,用于网络交互,此处随便写了一个。

public class MainActivityPresenter extends BasePresenter<MainActivityCallView>{
    private IML_MainAService mService=new IML_MainAService() {
        @Override
        public void api_login() {
            mView.loginSuccess();
        }
    };

    public void login() {
        mService.api_login();

    }
}

IML_MainAService:代码如下,就是随便写了几个方法,是那么个意思。

public interface IML_MainAService {
     void api_login();
}

最后,很重要的一点:命名规范,一个规范的命名对于项目是很重要的,不管这个项目是不是你去维护。有人习惯用缩写,我个人认为能不用缩写就不用,每人会猜你这是干嘛的,尽量用全拼(英语)。

说说这个项目的mvp命名规范:

功能 命名规范
Presenter 带Activity的名称 比如是MainActivity的Presenter 就要写MainActivityPresenter
网络交互 在Presenter中与远程服务器交互的接口 都以IML_开头后跟具体哪个类的全拼,此处作者有自己的标准 Activity和Fragment都取首字母 比如 IML_MainAService 则是 MainActivity的Presenter中网络交互接口
IBaseView 所有的IBaseView子类都应当以主类功能命名,并且后缀固定 作者使用的是CallView结尾,当然也可以使用CallBack结尾,清晰易懂,回调处理比如 :MainActivityCallView 就是主界面的回调接口类

好了MVP模式就说到这里,稍后会上传各种资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值