Android开发Android开发经验谈

Android 组件化实践

2019-10-20  本文已影响0人  折剑游侠

组件化MVP+Retrofit+Rxjava,项目使用kotlin,路由框架Arouter。

1. 新建项目New Project
2. 根目录创建config.gradle文件,统一管理依赖库。
ext {
    android = [
            compileSdkVersion: 28,
            applicationId    : "com.chenxuan.kotlinmvp",
            minSdkVersion    : 21,
            targetSdkVersion : 28,
            versionCode      : 1,
            versionName      : "1.0.0",
    ]

    versions = [
            kotlin             : "1.3.40",
            androidx_core      : "1.1.0",
            appcompat          : "1.1.0",
            constraintlayout   : "1.1.3",
            rxjava             : "2.2.9",
            rxandroid          : "2.1.1",
            retrofit           : "2.6.0",
            converter_gson     : "2.6.0",
            adapter_rxjava2    : "2.6.0",
            gson               : "2.8.5",
            logging_interceptor: "4.0.0-alpha02",
            utilcodex          : "1.25.9",
            arouter            : "1.5.0",
            arouter_compiler   : "1.2.2",
            autosize           : "1.1.2",
            glide              : "4.9.0",
            glide_compiler     : "4.9.0",
            material_dialogs   : "0.9.6.0",
            logger             : "2.2.0",
            immersionbar       : "3.0.0-beta05",
            recyclerViewAdapter: "2.9.30",
            rxpermissions      : "0.10.2",
            matisse            : "0.5.2-beta3",
            eventbus           : "3.1.1",
            leakcanary         : "2.0-alpha-2",
            leaksentry         : "2.0-alpha-2",
            multidex           : "1.0.3"
    ]

    dependencies = [
            kotlin             : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlin",
            androidx_core      : "androidx.core:core-ktx:$versions.androidx_core",
            appcompat          : "androidx.appcompat:appcompat:$versions.appcompat",
            constraintlayout   : "androidx.constraintlayout:constraintlayout:$versions.constraintlayout",
            rxjava             : "io.reactivex.rxjava2:rxjava:$versions.rxjava",
            rxandroid          : "io.reactivex.rxjava2:rxandroid:$versions.rxandroid",
            retrofit           : "com.squareup.retrofit2:retrofit:$versions.retrofit",
            converter_gson     : "com.squareup.retrofit2:converter-gson:$versions.converter_gson",
            adapter_rxjava2    : "com.squareup.retrofit2:adapter-rxjava2:$versions.adapter_rxjava2",
            gson               : "com.google.code.gson:gson:$versions.gson",
            logging_interceptor: "com.squareup.okhttp3:logging-interceptor:$versions.logging_interceptor",
            //AndroidUtilCode---https://github.com/Blankj/AndroidUtilCode
            utilcodex          : "com.blankj:utilcodex:$versions.utilcodex",
            //ARouter---https://github.com/alibaba/ARouter/blob/master/README_CN.md
            arouter            : "com.alibaba:arouter-api:$versions.arouter",
            arouter_compiler   : "com.alibaba:arouter-compiler:$versions.arouter_compiler",
            //屏幕适配---https://github.com/JessYanCoding/AndroidAutoSize
            autosize           : "me.jessyan:autosize:$versions.autosize",
            //glide---https://github.com/bumptech/glide
            glide              : "com.github.bumptech.glide:glide:$versions.glide",
            glide_compiler     : "com.github.bumptech.glide:compiler:$versions.glide_compiler",
            //dialog---https://github.com/afollestad/material-dialogs
            material_dialogs   : "com.afollestad.material-dialogs:commons:$versions.material_dialogs",
            //日志---https://github.com/orhanobut/logger
            logger             : "com.orhanobut:logger:$versions.logger",
            //状态栏---https://github.com/gyf-dev/ImmersionBar
            immersionbar       : "com.gyf.immersionbar:immersionbar:$versions.immersionbar",
            //adapter---https://www.jianshu.com/p/b343fcff51b0
            recyclerViewAdapter: "com.github.CymChad:BaseRecyclerViewAdapterHelper:$versions.recyclerViewAdapter",
            //权限---https://github.com/tbruyelle/RxPermissions
            rxpermissions      : "com.github.tbruyelle:rxpermissions:$versions.rxpermissions",
            //图片选择器---https://github.com/zhihu/Matisse
            matisse            : "com.zhihu.android:matisse:$versions.matisse",
            //EventBus---https://github.com/greenrobot/EventBus
            eventbus           : "org.greenrobot:eventbus:$versions.eventbus",
            //内存泄漏---https://github.com/square/leakcanary/wiki/Migrating-to-LeakCanary-2.0
            leakcanary         : "com.squareup.leakcanary:leakcanary-android:$versions.leakcanary",
            leaksentry         : "com.squareup.leakcanary:leaksentry:$versions.leaksentry",
            //65536分包
            multidex           : "com.android.support:multidex:$versions.multidex"
    ]
}

打开app下build.gradle修改如下

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

def root_android = rootProject.ext.android
def root_dependencies = rootProject.ext.dependencies

android {
    compileSdkVersion root_android.compileSdkVersion
    defaultConfig {
        applicationId root_android.applicationId
        minSdkVersion root_android.minSdkVersion
        targetSdkVersion root_android.targetSdkVersion
        versionCode root_android.versionCode
        versionName root_android.versionName
        multiDexEnabled true

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

kapt {
    arguments {
        arg("AROUTER_MODULE_NAME", project.getName())
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    kapt root_dependencies.arouter_compiler
}

简单说明下
def root_android = rootProject.ext.android
def root_dependencies = rootProject.ext.dependencies

rootProject.ext.android->config.gradle下android[]
rootProject.ext.dependencies->confing.gradle下dependencies[]。

kapt {
    arguments {
        arg("AROUTER_MODULE_NAME", project.getName())
    }
}

dependencies {
    ...
    kapt root_dependencies.arouter_compiler
}

这段代码是Arouter配置,无需改动。

3. 新建base module,选择library。此mudole统一管理依赖库。修改base下build.gradle:
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

def root_android = rootProject.ext.android
def root_dependencies = rootProject.ext.dependencies

android {
    compileSdkVersion root_android.compileSdkVersion
    defaultConfig {
        minSdkVersion root_android.minSdkVersion
        targetSdkVersion root_android.targetSdkVersion
        versionCode root_android.versionCode
        versionName root_android.versionName
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

kapt {
    arguments {
        arg("AROUTER_MODULE_NAME", project.getName())
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    api root_dependencies.kotlin
    api root_dependencies.androidx_core
    api root_dependencies.appcompat
    api root_dependencies.constraintlayout
    api root_dependencies.rxjava
    api root_dependencies.rxandroid
    api root_dependencies.retrofit
    api root_dependencies.converter_gson
    api root_dependencies.adapter_rxjava2
    api root_dependencies.gson
    api root_dependencies.logging_interceptor
    api root_dependencies.utilcodex
    api root_dependencies.arouter
    kapt root_dependencies.arouter_compiler
    api root_dependencies.autosize
    api root_dependencies.glide
    annotationProcessor root_dependencies.glide_compiler
    api root_dependencies.material_dialogs
    api root_dependencies.logger
    api root_dependencies.immersionbar
    api root_dependencies.recyclerViewAdapter
    api root_dependencies.rxpermissions
    api root_dependencies.matisse
    api root_dependencies.eventbus
    api root_dependencies.multidex
}

这里用api引入依赖,其它moudle依赖base后也能使用这些依赖库。

4. 新建common module,选择library。此module封装项目基本框架,MVP、网络库等。修改common下build.gradle:
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

def root_android = rootProject.ext.android

android {
    compileSdkVersion root_android.compileSdkVersion
    defaultConfig {
        minSdkVersion root_android.minSdkVersion
        targetSdkVersion root_android.targetSdkVersion
        versionCode root_android.versionCode
        versionName root_android.versionName
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    api project(path: ':base')
}

api project(path: ':base')

common依赖base,可使用base下依赖库,不清楚的可以查看api和implementation区别。这里引入base使用api,业务moudle引入common也可使用base下依赖库。

接下来在common中写mvp框架,网络框架,utils等。复杂的功能,如网络框架可以单独抽出来,写成net module。

5. 业务module,新建login module。根目录下gradle.properties新增变量isLoginModule=true。
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
#控制module true为library,false为application
isLoginModule=true

修改login下build.gradle:

if (isLoginModule.toBoolean()) {
    apply plugin: 'com.android.library'
} else {
    apply plugin: 'com.android.application'
}
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

def root_android = rootProject.ext.android
def root_dependencies = rootProject.ext.dependencies

android {
    compileSdkVersion root_android.compileSdkVersion
    defaultConfig {
        minSdkVersion root_android.minSdkVersion
        targetSdkVersion root_android.targetSdkVersion
        versionCode root_android.versionCode
        versionName root_android.versionName

        if (!isLoginModule.toBoolean()) {
            //单独运行时需要applicationId 
            applicationId "com.chenxuan.kotlinmvp.login"
        }
    }

    sourceSets {
        main {
            //使用不同的 AndroidManifest.xml 文件
            if (isLoginModule.toBoolean()) {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

kapt {
    arguments {
        arg("AROUTER_MODULE_NAME", project.getName())
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(path: ':common')
    kapt root_dependencies.arouter_compiler
}

通过isLoginModule控制业务module是否作为application单独编译运行。isLoginModule写在gradle.properties文件中每次修改都会触发编译。

if (isLoginModule.toBoolean()) {
    apply plugin: 'com.android.library'
} else {
    apply plugin: 'com.android.application'
}

android {
    defaultConfig {
        ...
        if (!isLoginModule.toBoolean()) {
            //单独运行时需要applicationId
            applicationId "com.chenxuan.kotlinmvp.login"
        }
    }
}

业务module为library/application时Manifest文件配置有差异,appapplication需要配置启动项,指定application等。

sourceSets {
        main {
            //使用不同的 AndroidManifest.xml 文件
            if (isLoginModule.toBoolean()) {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
            }
        }
    }

在对应目录新建配置文件AndroidManifest.xml。业务module为library时,main下AndroidManifest.xml比较简单。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.chenxuan.login">

    <application android:allowBackup="true">

        <activity android:name=".ui.LoginActivity" />
    </application>

</manifest>

业务module为application时main下新建package mainfest,mainfest下新建配置文件AndroidManifest.xml,目录对应之前配置即可。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          package="com.chenxuan.login">

    <application
            android:allowBackup="true"
            android:name="com.chenxuan.common.base.BaseApplication"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme"
            tools:ignore="GoogleAppIndexingWarning">
        <activity android:name="com.chenxuan.login.ui.LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>
6. login module创建成功后,别忘了在app中依赖login。app下build.gralde:
dependencies {
    ...
    if (isLoginModule.toBoolean()) {
        implementation project(path: ':login')
    }
}

这里说个大概,嫌麻烦也可以看看我的实现:https://github.com/xuanduoduo/MVP

上一篇下一篇

猜你喜欢

热点阅读