Android 之MVP模式

来源:互联网 发布:天天特价9.9淘宝网 编辑:程序博客网 时间:2024/06/05 02:41

前言:如果童鞋对于接口回调,多态,泛型(这个很重要)不是特别熟练,或者不是特别了解,建议还是不要使用这种模式。先谢谢常规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模式就说到这里,稍后会上传各种资源。

0 0
原创粉丝点击