Android MVP架构搭建

Android MVP架构搭建

让我们从零开始搭建一个通用的MVP架构

统一依赖和组件化

我们可以把依赖库,还有一些定义的版本好,写成统一的config.gradle:

//配置版本号以及依赖库
ext {
    android = [
            applicationId        : "com.linrh.granary",
            compileSdkVersion    : 28,
            minSdkVersion        : 19,
            targetSdkVersion     : 28,
            buildToolsVersion    : "28.0.3",
            versionCode          : 1,
            versionName          : "1.0.1",
    ]

    //配置java版本
    compileOptions = [
            sourceCompatibility: JavaVersion.VERSION_1_8,
            targetCompatibility: JavaVersion.VERSION_1_8,
    ]

    //项目统一使用到的依赖管理
    //使用implementation rootProject.ext.dependencies.xxx的方式进行引用
    //比如 implementation rootProject.ext.dependencies.appcompatx
    dependencies = [
            //自带
            appcompatV7            : "com.android.support:appcompat-v7:28.0.0",
            design                 : "com.android.support:design:28.0.0",
            recyclerview           : "com.android.support:recyclerview-v7:28.0.0",
            cardview               : "com.android.support:cardview-v7:28.0.0",
            annotations            : "com.android.support:support-annotations:28.0.0",
            multidex               : "com.android.support:multidex:1.0.3",
            constraintLayout       : "com.android.support.constraint:constraint-layout:1.1.3",
            flexbox                : "com.google.android:flexbox:1.0.0",

            //这是androidx的导入包
            appcompatx: "androidx.appcompat:appcompat:1.0.2",
            materialx: "com.google.android.material:material:1.0.0",
            constraintLayoutx: "androidx.constraintlayout:constraintlayout:1.1.3",
            annotationx: "androidx.annotation:annotation:1.0.2",
            lifecyclex :"androidx.lifecycle:lifecycle-extensions:2.0.0",



            //test
            androidJUnitRunner       : "android.support.test.runner.AndroidJUnitRunner",
            junit                    : "junit:junit:4.12",
            runner                   : "com.android.support.test:runner:1.0.1",
            espressocore            : "com.android.support.test.espresso:espresso-core:3.1.1",
            espressocontrib         : "com.android.support.test.espresso:espresso-contrib:3.1.1",
            espressointents         : "com.android.support.test.espresso:espresso-intents:3.1.1",

            //这是androidx的导入包
            androidJUnitRunner       : "androidx.test.runner.AndroidJUnitRunner",
            runnerx :"androidx.test:runner:1.1.1",
            espressocorex :"androidx.test.espresso:espresso-core:3.1.1",
            espressocontribx : "androidx.test.espresso:espresso-contrib:3.1.1",
            espressointentsx : "androidx.test.espresso:espresso-intents:3.1.1",



            //kotlin
            kotlinCoroutinesCore  : "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0",


            //注解
            butterknife            : "com.jakewharton:butterknife:8.8.1",
            butterknifeCompiler    : "com.jakewharton:butterknife-compiler:8.8.1",
            butterknifeGradlePlugin: "com.jakewharton:butterknife-gradle-plugin:8.8.1",

            //rxjava
            rxandroid2               : "io.reactivex.rxjava2:rxandroid:2.1.0",
            rxjava2                  : "io.reactivex.rxjava2:rxjava:2.2.3",

            rxlifecycle2             : "com.trello.rxlifecycle2:rxlifecycle:2.2.2",
            rxlifecycle2android     : "com.trello.rxlifecycle2:rxlifecycle-android:2.2.2",
            rxlifecycle2components  : "com.trello.rxlifecycle2:rxlifecycle-components:2.2.2",

            dagger2                  : "com.google.dagger:dagger:2.19",
            dagger2android          : "com.google.dagger:dagger-android:2.19",
            dagger2androidSupport  : "com.google.dagger:dagger-android-support:2.19",
            dagger2compiler         : "com.google.dagger:dagger-compiler:2.19",
            dagger2androidProcessor: "com.google.dagger:dagger-android-processor:2.19",


            //通信
            eventbus               : "org.greenrobot:eventbus:3.1.1",

            //序列化
            gson                   : "com.google.code.gson:gson:2.8.5",

            //图片
            glide                  : "com.github.bumptech.glide:glide:4.8.0",
            glideCompiler          : "com.github.bumptech.glide:compiler:4.8.0",
            glideOkhttp3           : "com.github.bumptech.glide:okhttp3-integration:4.8.0",
            picasso                 : "com.squareup.picasso:picasso:2.5.2",

            //网络
            rxHttp                 : "com.github.goweii:RxHttp:2.2.9",
            retrofit                 : "com.squareup.retrofit2:retrofit:2.4.0",
            retrofitConverterGson  : "com.squareup.retrofit2:converter-gson:2.4.0",
            retrofitAdapterRxjava2 : "com.squareup.retrofit2:adapter-rxjava2:2.4.0",
            okhttp3                  : "com.squareup.okhttp3:3.11.0",
            okhttpUrlconnection     : "com.squareup.okhttp:okhttp-urlconnection:2.0.0",

            //权限
            anyPermission          : "com.github.goweii:AnyPermission:1.1.2",

            //浏览器
            agentWeb               : "com.just.agentweb:agentweb:4.0.0",
            persistentCookieJar    : "com.github.franmontiel:PersistentCookieJar:v1.0.1",

            //缓存
            disklrucache           : "com.jakewharton:disklrucache:2.0.2",

            //懒加载
            lazyfragment           : "com.github.goweii.LazyFragment:lazyfragment:1.1.2",

            //组件化
            arouterApi             : "com.alibaba:arouter-api:1.4.1",
            arouterCompiler        : "com.alibaba:arouter-compiler:1.2.2",


            //异常
            buglyCrashreport       : "com.tencent.bugly:crashreport:3.1.0",
            crashActivity          : "cat.ereza:customactivityoncrash:2.2.0",
            canarydebug             : "com.squareup.leakcanary:leakcanary-android:1.6.3",
            canaryrelease           : "com.squareup.leakcanary:leakcanary-android-no-op:1.6.3",

            //布局相关
            bravh                  : "com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.46",
            smartRefreshLayout     : "com.scwang.smartrefresh:SmartRefreshLayout:1.1.0",
            smartRefreshHorizontal : "com.scwang.smartrefresh:SmartRefreshHorizontal:1.0.0-beta-1",
            anyDialog              : "com.github.goweii:AnyDialog:3.0.3",
            anyLayer               : "com.github.goweii:AnyLayer:3.2.2",
            actionBarEx            : "com.github.goweii:ActionBarEx:3.2.1",
            percentImageView       : "com.github.goweii:PercentImageView:1.0.2",
            roundedimageview       : "com.makeramen:roundedimageview:2.3.0",
            circleimageview        : "de.hdodenhof:circleimageview:2.2.0",
            magicIndicator         : "com.github.hackware1993:MagicIndicator:1.6.0",
            photoView              : "com.github.chrisbanes:PhotoView:2.1.3",
            materialProgressBar    : "me.zhanghai.android.materialprogressbar:library:1.4.2",
            realtimeBlurView       : "com.github.mmin18:realtimeblurview:1.1.2",
            banner                 : "com.youth.banner:banner:1.4.10",
            revealLayout           : "com.github.goweii:RevealLayout:1.2.1",
            anyView                : "com.github.goweii:AnyView:1.0.2",
            keyboardCompat         : "com.github.goweii:KeyboardCompat:1.0.0",
            swipelayout            : "com.daimajia.swipelayout:library:1.2.0@aar",
            multiStateView         : "com.github.Kennyc1012:MultiStateView:1.3.2",
            pictureSelector        : "com.github.goweii:PictureSelector:v2.3.1",
            swipeBack              : "com.github.goweii:SwipeBack:1.0.7",
            tinypinyin             : "com.github.promeg:tinypinyin:2.0.3",
            blurred                : "com.github.goweii:blurred:1.3.0",
            lottie                 : "com.airbnb.android:lottie:2.7.0",

            autolayout               : "com.zhy:autolayout:1.4.5",
            pickerview               : "com.contrarywind:Android-PickerView:4.1.3",
            photoview                : "com.github.chrisbanes:PhotoView:2.1.3",
            paginate                 : "com.github.markomilos:paginate:0.5.1",
            autosize                 : "me.jessyan:autosize:1.1.1",
            statusbar                : "com.jaeger.statusbarutil:library:1.5.1",

            //数据库
            greendao                 : "org.greenrobot:greendao:3.2.2",
            greendaoSqlcipher        :  "net.zetetic:android-database-sqlcipher:3.5.6",

            //日志
            timber                   : "com.jakewharton.timber:timber:4.7.1",
            
    ]
}

然后再配置好root下面的build.gradle,并引入config.gradle
此处增加了多个地址,可以加快依赖库下载和编译。

//先引入config.gradle
apply from: "config.gradle"
buildscript {
    //kotlin support
    ext.kotlin_version = '1.3.30'

    repositories {
        maven { url "https://jitpack.io" }
        google()
        jcenter()
        maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local' }
        maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
//        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
        // 华为obs
        maven { url 'https://mirrors.huaweicloud.com/repository/maven/huaweicloudsdk' }
        maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
        //自定义组件
        dependencies {

            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
            classpath 'com.android.tools.build:gradle:3.5.0'
            //classpath 'com.android.tools.build:gradle:3.3.2'
            //classpath 'com.android.tools.build:gradle:3.2.0'
            //classpath "io.realm:realm-gradle-plugin:5.12.0-SNAPSHOT"
            //classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-SNAPSHOT'
            classpath 'com.jakewharton:butterknife-gradle-plugin:10.0.0'
            //classpath 'com.jakewharton:butterknife-gradle-plugin:8.4.0'

            //greendao
            classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'

            //kotlin
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
            classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"

            //arouter
            classpath "com.alibaba:arouter-register:1.0.2"

            //aop
            //classpath "com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4"

        }
        //maven { url uri('./my-plugins/release-plugin') }

    }
}

allprojects {
    repositories {
        maven { url "https://jitpack.io" }
        google()
        jcenter()
        maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local' }
        maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
//        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
        // 华为obs
        maven { url 'https://mirrors.huaweicloud.com/repository/maven/huaweicloudsdk' }
        maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

无论是library,还是application,有一些共同的配置,比如编译版本号这些,是通用的,所以再抽出一层 base.gradle

//共有的依赖条件声明到此处。
android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    buildToolsVersion rootProject.ext.android.buildToolsVersion

    defaultConfig {
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
        testInstrumentationRunner rootProject.ext.dependencies.androidJUnitRunner
    }
    buildTypes {
        release {
            debuggable false

            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            debuggable true
        }
    }
    compileOptions {
        sourceCompatibility rootProject.ext.compileOptions.sourceCompatibility
        targetCompatibility rootProject.ext.compileOptions.targetCompatibility
        //incremental true
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    //implementation rootProject.ext.dependencies.appcompatx
}

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support') {
            if (!requested.name.startsWith("multidex")) {
                details.useVersion rootProject.ext.versions.appcompat
            } else {
                details.useVersion rootProject.ext.versions.multidex
            }
        }
    }
}

此时,application的gradle可以如此:

apply plugin: 'com.android.application'
apply from: "../basic.gradle"
android {

    defaultConfig {
        applicationId  rootProject.ext.android.applicationId

        renderscriptSupportModeEnabled true
        ndk {
            abiFilters /*'armeabi' ,*/'armeabi-v7a'/*, 'arm64-v8a'*/
        }

    }
    buildTypes {
        release {
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    output.outputFileName = "$applicationId-v${defaultConfig.versionName}.apk"
                }
            }
        }
    }
    resourcePrefix ""
}

dependencies {
    implementation rootProject.ext.dependencies.appcompatx
    implementation rootProject.ext.dependencies.constraintLayoutx
    implementation rootProject.ext.dependencies.annotationx
    implementation rootProject.ext.dependencies.lifecyclex
    implementation rootProject.ext.dependencies.materialx


//    implementation rootProject.ext.dependencies.appcompatV7
      annotationProcessor 'com.jakewharton:butterknife-compiler:10.0.0'
    implementation 'com.jakewharton:butterknife:10.0.0'
      implementation rootProject.ext.dependencies.eventbus
//    implementation rootProject.ext.dependencies.cardview
//    implementation rootProject.ext.dependencies.flexbox
//    implementation rootProject.ext.dependencies.realtimeBlurView
//    implementation rootProject.ext.dependencies.agentWeb
//    implementation rootProject.ext.dependencies.banner
//    implementation rootProject.ext.dependencies.persistentCookieJar
//    implementation rootProject.ext.dependencies.revealLayout
//    implementation rootProject.ext.dependencies.keyboardCompat
//    implementation rootProject.ext.dependencies.swipelayout
//    implementation rootProject.ext.dependencies.disklrucache
//    implementation rootProject.ext.dependencies.multiStateView
//    implementation rootProject.ext.dependencies.pictureSelector
//    implementation rootProject.ext.dependencies.buglyCrashreport
//    implementation rootProject.ext.dependencies.crashActivity
}

library可以这么写:

apply plugin: 'com.android.library'
apply from: "../basic.gradle"

android {

}

dependencies {
    implementation rootProject.ext.dependencies.appcompatx
}

这时候,如果有实现library可以配置成为application,直接编译运行,该怎么弄呢?

settings.gradle里面,新增

#isBuildModule 为 true 时可以使每个组件独立运行, false 则可以将所有组件集成到宿主 App 中
isBuildModule=false

在模块的build.gradle中改动为:

if (isBuildModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
apply from: "../basic.gradle"

android {
    defaultConfig {
        if (isBuildModule.toBoolean()) {
            applicationId "com.linrh.hellotest"
        }


    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation rootProject.ext.dependencies.appcompatx
    implementation rootProject.ext.dependencies.constraintLayoutx

    testImplementation rootProject.ext.dependencies.junit
    androidTestImplementation rootProject.ext.dependencies.runnerx
    androidTestImplementation rootProject.ext.dependencies.espressocorex
}


此时就可以编译为独立的APP了。

MVP框架搭建

MVP框架简单来说,就是M层和V层中间抽像了一层接口层P层,P层持有V层的引用以及M层的对象,然后充当中间的媒介。
可以抽象出统一的模版

抽象出view

import android.content.Context;

/**
 * 主要界面的基础接口
 */
public interface IMvpView {
    Context getContext();
    void showLoadingDialog();
    void dismissLoadingDialog();
    void clearLoading();
}

抽象出对于的P

package com.linrh.base.mvp;

import android.content.Context;

public abstract class MvpPresenter <V extends IMvpView>{

    protected Context context;
    private V baseView;

    public void attach(V baseView) {
        this.baseView = baseView;
        context = baseView.getContext();
    }

    public void detach() {
        baseView = null;
        context = null;
    }

    public V getBaseView() {
        return baseView;
    }

    public boolean isAttach() {
        return baseView != null;
    }

    public Context getContext() {
        return context;
    }

    public void showLoadingDialog() {
        if (baseView != null) {
            baseView.showLoadingDialog();
        }
    }

    public void dismissLoadingDialog() {
        if (baseView != null) {
            baseView.dismissLoadingDialog();
        }
    }

}

可以设定一个统一的Activity

package com.linrh.base.mvp;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;

import androidx.annotation.Nullable;

public abstract class MvpActivity<P extends MvpPresenter> extends Activity
implements IMvpView{

    public P presenter;

    /**
     * 初始化窗口
     */
    protected void initWindow() {
    }

    /**
     * 获取布局资源文件。
     * 返回布局文件的ID
     */
    protected abstract int getLayoutId();

    /**
     * 初始化presenter
     */
    @Nullable
    protected abstract P initPresenter();

    /**
     * 初始化控件
     */
    protected abstract void initView();

    /**
     * 绑定数据
     */
    protected abstract void loadData();

    /**
     * 初始化
     */
    protected void initialize() {
        initView();
        loadData();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initWindow();
        if (getLayoutId() > 0) {
            setContentView(getLayoutId());
        }
        presenter = initPresenter();
        if (presenter != null) {
            //V 与 P 绑定
            presenter.attach(this);
        }
        initialize();
    }

    @Override
    protected void onDestroy() {
        if (presenter != null) {
            presenter.detach();
        }
        super.onDestroy();
    }

    @Override
    public Context getContext() {
        return getActivity();
    }

    protected Activity getActivity() {
        return this;
    }

}

或者一个统一的fragment

package com.linrh.base.mvp;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public abstract class MvpFragment<P extends MvpPresenter> extends Fragment
implements IMvpView{

    /**
     * 界面布局
     */
    protected View mRootView = null;
    /**
     * 标识界面是否创建
     */
    protected boolean mViewCreated = false;

    public P presenter;

    /**
     * 初始化窗口
     */
    protected void initWindow() {
    }

    /**
     * 获取布局资源文件。
     * 返回布局文件的ID
     */
    protected abstract int getLayoutId();

    /**
     * 初始化presenter
     */
    @Nullable
    protected abstract P initPresenter();

    /**
     * 初始化控件
     */
    protected abstract void initView();

    /**
     * 绑定数据
     */
    protected abstract void loadData();

    /**
     * 初始化
     */
    protected void initialize() {
        initView();
        loadData();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        /**
         * 初始化界面
         */
        if (mRootView == null) {
            final int layoutId = getLayoutId();
            if (layoutId > 0) {
                mRootView = inflater.inflate(getLayoutId(), container, false);
            }
        }
        mViewCreated = true;
        return mRootView;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        presenter = initPresenter();
        if (presenter != null) {
            presenter.attach(this);
        }
        initialize();
    }

    @Override
    public void onDestroyView() {
        if (presenter != null) {
            presenter.detach();
        }
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public Context getContext() {
        return getActivity();
    }

    public Fragment getFragment() {
        return this;
    }


}

为了便于理解,此处回顾下fragment的生命周期
fragment生命周期

  • setUserVisibleHint():设置Fragment可见或者不可见时会调用此方法。在该方法里面可以通过调用getUserVisibleHint()获得Fragment的状态是可见还是不可见的,如果可见则进行懒加载操作。
  • onAttach():执行该方法时,Fragment与Activity已经完成绑定,该方法有一个Activity类型的参数,代表绑定的Activity,这时候你可以执行诸如mActivity = activity的操作。
  • onCreate():初始化Fragment。可通过参数savedInstanceState获取之前保存的值。
  • onCreateView():初始化Fragment的布局。加载布局和findViewById的操作通常在此函数内完成,但是不建议执行耗时的操作,比如读取数据库数据列表。
  • onActivityCreated():执行该方法时,与Fragment绑定的Activity的onCreate方法已经执行完成并返回,在该方法内可以进行与Activity交互的UI操作,所以在该方法之前Activity的onCreate方法并未执行完成,如果提前进行交互操作,会引发空指针异常。
  • onStart():执行该方法时,Fragment由不可见变为可见状态。
  • onResume():执行该方法时,Fragment处于活动状态,用户可与之交互。
  • onPause():执行该方法时,Fragment处于暂停状态,但依然可见,用户不能与之交互。
  • onSaveInstanceState():保存当前Fragment的状态。该方法会自动保存Fragment的状态,比如EditText键入的文本,即使Fragment被回收又重新创建,一样能恢复EditText之前键入的文本。
  • onStop():执行该方法时,Fragment完全不可见。
  • onDestroyView():销毁与Fragment有关的视图,但未与Activity解除绑定,依然可以通过onCreateView方法重新创建视图。通常在ViewPager+Fragment的方式下会调用此方法。
  • onDestroy():销毁Fragment。通常按Back键退出或者Fragment被回收时调用此方法。
  • onDetach():解除与Activity的绑定。在onDestroy方法之后调用。

一般Activity继承这个MvpActivity后,可能会用到ButterKnife等,可以在封装一层BaseActivity

package com.linrh.base.base;

import com.linrh.base.mvp.MvpActivity;
import com.linrh.base.ui.LoadingDialog;

import org.greenrobot.eventbus.EventBus;

import butterknife.ButterKnife;
import butterknife.Unbinder;


/**
 * @author Cuizhen
 * @version v1.0.0
 * @date 2018/4/4-下午1:23
 */
public abstract class BaseActivity<P extends BasePresenter> extends MvpActivity<P> {
    private LoadingDialog mLoadingDialog = null;
    private Unbinder mUnbinder = null;

    /**
     * 是否注册事件分发,默认不绑定
     */
    protected boolean isRegisterEventBus() {
        return false;
    }

    @Override
    protected void initialize() {
        mUnbinder = ButterKnife.bind(this);
        if (isRegisterEventBus()) {
            EventBus.getDefault().register(this);
        }
        super.initialize();
    }

    @Override
    protected void onDestroy() {
        clearLoading();
        super.onDestroy();
        if (isRegisterEventBus()) {
            EventBus.getDefault().unregister(this);
        }
        if (mUnbinder != null) {
            mUnbinder.unbind();
        }
    }

    @Override
    public void showLoadingDialog() {
        if (mLoadingDialog == null) {
            mLoadingDialog = LoadingDialog.with(getContext());
        }
        mLoadingDialog.show();
    }

    @Override
    public void dismissLoadingDialog() {
        if (mLoadingDialog != null) {
            mLoadingDialog.dismiss();
        }
    }

    @Override
    public void clearLoading() {
        if (mLoadingDialog != null) {
            mLoadingDialog.clear();
        }
        mLoadingDialog = null;
    }

}

isRegisterEventBus函数,可以指定是否需要EventBus.

BasePresenter:

package com.linrh.base.base;

import com.linrh.base.mvp.MvpPresenter;

/**
 * 此处可以用来做一些生命周期的控制
 * 比如对rxjava的请求作为统一的管理
 * @param <V>
 */
public class BasePresenter<V extends BaseView> extends MvpPresenter<V> {

    @Override
    public void attach(V baseView) {
        super.attach(baseView);
    }

    @Override
    public void detach() {
        super.detach();
    }
}

BaseView:

package com.linrh.base.base;


import com.linrh.base.mvp.IMvpView;

public interface BaseView extends IMvpView {
}

现在我们开始创建一个模块来实现登录的功能。

首先设置下目录
login module
新建LoginView,添加自定义的界面动作

package com.linrh.granary.module.login.view;

import android.content.Context;

import com.linrh.base.base.BaseView;


public interface LoginView extends BaseView {

    void loginSuccess(int code, LoginBean data);
    void loginFailed(int code, String msg);
}

定义模块的presenter

package com.linrh.granary.module.login.presenter;

import com.linrh.base.base.BasePresenter;
import com.linrh.granary.module.login.model.LoginBean;
import com.linrh.granary.module.login.view.LoginView;

public class LoginPresenter extends BasePresenter<LoginView> {

    public void login(String userName, String password){
        //开始请求
        showLoadingDialog();
        
        //请求成功
        if (isAttach()){
            getBaseView().loginSuccess(00,new LoginBean());
        }
        
        //失败
        if (isAttach()){
            getBaseView().loginFailed(00,"fail");
        }
        
        //结束
        dismissLoadingDialog();
    }
}

其中根据需求,完成相应的逻辑操作。最后实现View层

package com.linrh.granary.module.login.activity;

import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;

import androidx.annotation.Nullable;

import com.linrh.base.base.BaseActivity;
import com.linrh.granary.R;
import com.linrh.granary.module.login.model.LoginBean;
import com.linrh.granary.module.login.presenter.LoginPresenter;
import com.linrh.granary.module.login.view.LoginView;

public class LoginActivity  extends BaseActivity<LoginPresenter> implements LoginView {

    ProgressBar loadingProgressBar;

    @Override
    protected int getLayoutId() {
        return R.layout.activity_login;
    }

    @Nullable
    @Override
    protected LoginPresenter initPresenter() {
        return new LoginPresenter();
    }

    @Override
    protected void initView() {
        final EditText usernameEditText = findViewById(R.id.username);
        final EditText passwordEditText = findViewById(R.id.password);
        final Button loginButton = findViewById(R.id.login);
        loadingProgressBar = findViewById(R.id.loading);

        loginButton.setEnabled(true);
        loginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                presenter.login(usernameEditText.getText().toString().trim(),
                        passwordEditText.getText().toString().trim());
            }
        });

    }

    @Override
    protected void loadData() {

    }


    @Override
    public void loginSuccess(int code, LoginBean data) {

    }

    @Override
    public void loginFailed(int code, String msg) {

    }

    @Override
    public void showLoadingDialog() {
        //super.showLoadingDialog();
        loadingProgressBar.setVisibility(View.VISIBLE);

    }

    @Override
    public void dismissLoadingDialog() {
        //super.dismissLoadingDialog();
        loadingProgressBar.setVisibility(View.GONE);

    }
}

简单来说,就是mvp定义基本关系,base初始化一些界面通用的注解和等待弹窗。最上层的MVP,用来做实际上的操作。

登录界面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值