Android 组件化开发

本篇简单谈谈Android及其搭建方案

浅谈对组件化的理解

什么是组件化?如何实现组件化?

不得不提的模块化

Android的模块化应用已久,它的使用让我们的代码变得整洁和易于维护。虽然我们有MVC、MVP以及MVVM等等,但是所有的M、所有的V以及所有的C或者P、VM堆叠在一起也是一件很头疼的事情。引入模块化后,根据项目的具体功能模块,分由不同的包管理,公共部分更是以库的形式引用,大大的提高了项目的可维护性,降低了协同开发在代码管理上的难度,使得项目结构更具层次感。

模块化的升级版组件化

回到最初提出的问题,什么是组件化?它是以具体业务为单元,对项目整体进行分割,并以Module的形式进行管理的一种构架方式。

使用组件化的好处

前面说到了,组件化是模块化的升级,这是从作用上来说的,他们也是有区别的。模块化更多的是站在开发的角度上,以功能为单位对项目整体进行分割;而组件化主要是以业务为单元。其次,在模块化时,除库以外,我们都只是以包的形式将各个模块进行分离,哪怕用到了Module,也大多不能独立编译。引入组件化之后,随着项目的逐渐增大,每个业务模块可以单独编译,加快了编译速度,同时也为单元模块测试提供了支持;多人开发只负责各自的业务,减少了版本管理中的代码冲突概率。

如何实现组件化

创建项目,并根据项目所包含业务进行搭建

‘:app’, ‘:major’, ‘:library’, ‘:account’, ‘:order’, ‘:goods’, ‘:business’, ‘:customer’, ‘:article’, ‘:prepurchase’, ‘:comment’

项目根目录下创建版本控制文件config.gradle,避免各个模块间版本冲突

ext {

    androidVersion = [
        compileSdkVersion : 28,
        minSdkVersion : 21,
        targetSdkVersion : 28,
        versionCode : 1,
        versionName : "1.0",
        testInstrumentationRunner : "android.support.test.runner.AndroidJUnitRunner"
    ]

    dependenciesVersion = [
        appcompat_v7 : 'com.android.support:appcompat-v7:28.0.0',
        constraint_layout : 'com.android.support.constraint:constraint-layout:1.1.3',
        junit : 'junit:junit:4.12',
        runner : 'com.android.support.test:runner:1.0.2',
        espresso_core : 'com.android.support.test.espresso:espresso-core:3.0.2',
        android_common_mvp :'com.github.ww7hcom:Android-common-mvp:1.0.9',
        android_common :'com.github.ww7hcom:Android-common:1.0.31',
        design : 'com.android.support:design:28.0.0',
        kotlin : 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31',
        gms_play : 'com.google.android.gms:play-services-ads:17.2.0',
        lifecycle_extensions : 'android.arch.lifecycle:extensions:1.1.1'
    ]

}

根目录build.gradle头部添加 apply from: ‘config.gradle’

apply from: 'config.gradle'

def androidVersion = ext.androidVersion
def dependenciesVersion = ext.dependenciesVersion

buildscript {

    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

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

gradle.properties文件添加各模块当前是否使用组件化

majorUseModule = true
orderUseModule = true
accountUseModule = true
goodsUseModule = true
businessUseModule = true
customerUseModule = true
articleUseModule = true
prepurchaseUseModule = true
commentUseModule = true

app壳build.gradle示例,根据各个模块是否使用组件化来判断是否需要作为库引入

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion androidVersion.compileSdkVersion
    defaultConfig {
        applicationId "com.ww7h.assistant"
        minSdkVersion androidVersion.minSdkVersion
        targetSdkVersion androidVersion.targetSdkVersion
        versionCode androidVersion.versionCode
        versionName androidVersion.versionName
        testInstrumentationRunner androidVersion.testInstrumentationRunner
        javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }


        javaCompileOptions{
            annotationProcessorOptions {
                includeCompileClasspath true
            }
        }

    }
    buildTypes {
        release {
            minifyEnabled false

        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }

}



dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation dependenciesVersion.kotlin
    implementation dependenciesVersion.appcompat_v7
    implementation dependenciesVersion.constraint_layout
    implementation dependenciesVersion.design

    testImplementation dependenciesVersion.junit
    androidTestImplementation dependenciesVersion.runner
    androidTestImplementation dependenciesVersion.espresso_core

    implementation dependenciesVersion.android_common_mvp
    implementation dependenciesVersion.android_common

    implementation project(path: ':library')

    if (majorUseModule.toBoolean()) {
        implementation project(path: ':major')
    }

    if (accountUseModule.toBoolean()) {
        implementation project(path: ':account')
    }
    if (orderUseModule.toBoolean()) {
        implementation project(path: ':order')
    }
    if (goodsUseModule.toBoolean()) {
        implementation project(path: ':goods')
    }
    if (businessUseModule.toBoolean()) {
        implementation project(path: ':business')
    }
    if (customerUseModule.toBoolean()) {
        implementation project(path: ':customer')
    }
    if (articleUseModule.toBoolean()) {
        implementation project(path: ':article')
    }
    if (prepurchaseUseModule.toBoolean()) {
        implementation project(path: ':prepurchase')
    }
    if (commentUseModule.toBoolean()) {
        implementation project(path: ':comment')
    }

}

major主模块build.gradle示例,其他模块类似major

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

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion androidVersion.compileSdkVersion


    defaultConfig {
        if (!majorUseModule.toBoolean()) {
            applicationId "com.ww7h.assistant.major"
        }
        minSdkVersion androidVersion.minSdkVersion
        targetSdkVersion androidVersion.targetSdkVersion
        versionCode androidVersion.versionCode
        versionName androidVersion.versionName
        testInstrumentationRunner androidVersion.testInstrumentationRunner

    }

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

    sourceSets {
        main {
            if (majorUseModule.toBoolean()) {
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            }
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation dependenciesVersion.kotlin
    implementation dependenciesVersion.appcompat_v7
    implementation dependenciesVersion.constraint_layout
    implementation dependenciesVersion.design
    testImplementation dependenciesVersion.junit
    androidTestImplementation dependenciesVersion.runner
    androidTestImplementation dependenciesVersion.espresso_core

    implementation dependenciesVersion.android_common_mvp
    implementation dependenciesVersion.android_common
    implementation project(path: ':library')

}

各个组件之间依赖关系如下图,均为单向依赖,除app,library外,其他组件间均无依赖关系

组件之间的通信

个人觉得各个组件之间的通信是做好组件化的关键,那么如何让这些没有相互依赖的组件间实现通信了?

路由ARouter

!!文档很详细,就不复制粘贴了

URL Scheme跳转

定义拦截器

<intent-filter>
    <data
        android:host="goods"
        android:path="/goodsDetail"
        android:port="8080"
        android:scheme="ww7h"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>

跳转代码

private void jump() {

    if (schemeValid("ww7h://goods:8080/goodsDetail?goodsId=100")) {
        Intent action = new Intent(Intent.ACTION_VIEW);
        action.setData(Uri.parse("ww7h://goods:8080/goodsDetail?goodsId=100"));
        startActivity(action);
    }
}

private boolean schemeValid(String url) {
    PackageManager manager = mContext.getPackageManager();
    Intent action = new Intent(Intent.ACTION_VIEW);
    action.setData(Uri.parse(url));
    List list = manager.queryIntentActivities(action, PackageManager.GET_RESOLVED_FILTER);
    return list != null && list.size() > 0;
}

包名加Activity类名跳转

var intent:Intent= Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
var cn : ComponentName = ComponentName("com.ww7h.assistant",
    "com.ww7h.assistant.major.v.MajorMainActivity");
intent.component = cn;
startActivity(intent);

自定义路由

对象传递跳转

!!根据app依赖了所有组件,library被所有组件依赖,得到:app可以调用所有组件类;library可以被所有组件调用

library定义接口,提供跳转、fragment获取、fragment显示功能
package com.ww7h.assistant.library;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import com.ww7h.common.mvp.views.BaseViewFragment;

/**
* ================================================
* 描述:
* 来源:     Android Studio.
* 项目名:   PurchasingAssistant
* 包名:     com.ww7h.assistant.library
* 创建时间:  2019-05-22 16:36
*
* @author ww  Github地址:https://github.com/ww7hcom
* ================================================
*/
public interface IClassManager {

    void jump(Context context, Intent intent, String route);

    void jumpForResult(Activity activity, Intent intent, String route, int requestCode);

    <F extends BaseViewFragment> F showFragment(Context context, FragmentManager fragmentManager, F f, F lastF, int frameLayoutId, String route);

    <F extends BaseViewFragment> F getFragment(String route);

    <F extends BaseViewFragment> F showFragment(Context context, FragmentManager fragmentManager, int frameLayoutId, String route);
}
library定义组件class管理器
package com.ww7h.assistant.library;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.FragmentManager;
import android.widget.Toast;
import com.ww7h.common.mvp.views.BaseViewFragment;

/**
* ================================================
* 描述:
* 来源:     Android Studio.
* 项目名:   PurchasingAssistant
* 包名:     com.ww7h.assistant.library
* 创建时间:  2019-05-21 20:42
*
* @author ww  Github地址:https://github.com/ww7hcom
* ================================================
*/
public class ModuleClassManager {

    private IClassManager iClassManager;

    private ModuleClassManager() {

    }

    private static class Instance {
        private static final ModuleClassManager INSTANCE = new ModuleClassManager();
    }

    public static ModuleClassManager getInstance() {
        return Instance.INSTANCE;
    }

    public void setIClassManager(IClassManager iClassManager) {
        this.iClassManager = iClassManager;
    }

    public void jump(Context context, Intent intent, String route) {
        if (iClassManager != null) {
            iClassManager.jump(context, intent, route);
        } else {
            Toast.makeText(context, "app中未注册监听", Toast.LENGTH_SHORT).show();
        }
    }

    public void jumpForResult(Activity activity, Intent intent, String route, int requestCode) {
        if (iClassManager != null) {
            iClassManager.jumpForResult(activity, intent, route, requestCode);
        } else {
            Toast.makeText(activity, "app中未注册监听", Toast.LENGTH_SHORT).show();
        }
    }

    public <F extends BaseViewFragment> F showFragment(Context context, FragmentManager fragmentManager, F f, F lastF, int frameLayoutId, String route) {
        if (iClassManager != null) {
            return iClassManager.showFragment(context, fragmentManager, f, lastF, frameLayoutId, route);
        } else {
            Toast.makeText(context, "app中未注册监听", Toast.LENGTH_SHORT).show();
        }
        return null;
    }

    public <F extends BaseViewFragment> F getFragment(String route) {
        if (iClassManager != null) {
            return iClassManager.getFragment(route);
        }
        return null;
    }

    public <F extends BaseViewFragment> F showFragment(Context context, FragmentManager fragmentManager, int frameLayoutId, String route) {
        if (iClassManager != null) {
            return iClassManager.showFragment( context,  fragmentManager,  frameLayoutId,  route);
        }
        return null;
    }


}
各个模块中均定义一个class管理器,用来注册各自模块中可供外部调用的类
package com.ww7h.assistant.article;

import com.ww7h.assistant.article.v.ArticleMainFragment;

import java.util.HashMap;

/**
* ================================================
* 描述:
* 来源:     Android Studio.
* 项目名:   ArticleClassManager
* 包名:     com.ww7h.assistant.article
* 创建时间:  2019-05-22 17:59
*
* @author ww  Github地址:https://github.com/ww7hcom
* ================================================
*/
public class ArticleClassManager {

    private final HashMap<String, Class<?>> activityMap = new HashMap<String, Class<?>>() {
        {
            put("article_article_main", MainActivity.class);
        }
    };

    private HashMap<String, Class<?>> fragmentMap = new HashMap<String, Class<?>>(){
        {
            put("article_article_main", ArticleMainFragment.class);
        }
    };

    private ArticleClassManager() {

    }

    private static class Instance {
        private static final ArticleClassManager INSTANCE = new ArticleClassManager();
    }

    public static ArticleClassManager getInstance() {
        return Instance.INSTANCE;
    }

    public HashMap<String, Class<?>> getActivityMap() {
        return activityMap;
    }

    public HashMap<String, Class<?>> getFragmentMap() {
        return fragmentMap;
    }
}
app中定义ClassManager,用来收集各个子组件供外部调用的类,并实现IClassManager
package com.ww7h.assistant;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.widget.Toast;
import com.ww7h.assistant.account.AccountClassManager;
import com.ww7h.assistant.article.ArticleClassManager;
import com.ww7h.assistant.business.BusinessClassManager;
import com.ww7h.assistant.comment.CommentClassManager;
import com.ww7h.assistant.customer.CustomerClassManager;
import com.ww7h.assistant.goods.GoodsClassManager;
import com.ww7h.assistant.major.MajorClassManager;
import com.ww7h.assistant.order.OrderClassManager;
import com.ww7h.assistant.prepurchase.PrePurchaseClassManager;
import com.ww7h.assistant.library.IClassManager;
import com.ww7h.common.mvp.views.BaseViewFragment;

import java.util.HashMap;
import java.util.Objects;

/**
* ================================================
* 描述:
* 来源:     Android Studio.
* 项目名:   PurchasingAssistant
* 包名:     com.ww7h.assistant
* 创建时间:  2019-05-22 16:08
*
* @author ww  Github地址:https://github.com/ww7hcom
* ================================================
*/
public class ClassManager implements IClassManager {

    private HashMap<String, Class<?>> activityMap = new HashMap<String, Class<?>>() {{

        putAll(AccountClassManager.getInstance().getActivityMap());
        putAll(ArticleClassManager.getInstance().getActivityMap());
        putAll(BusinessClassManager.getInstance().getActivityMap());
        putAll(CommentClassManager.getInstance().getActivityMap());
        putAll(CustomerClassManager.getInstance().getActivityMap());
        putAll(GoodsClassManager.getInstance().getActivityMap());
        putAll(MajorClassManager.Companion.getInstance().getActivityMap());
        putAll(OrderClassManager.getInstance().getActivityMap());
        putAll(PrePurchaseClassManager.getInstance().getActivityMap());

    }};

    private HashMap<String, Class<?>> fragmentMap = new HashMap<String, Class<?>>() {{

        putAll(AccountClassManager.getInstance().getFragmentMap());
        putAll(ArticleClassManager.getInstance().getFragmentMap());
        putAll(BusinessClassManager.getInstance().getFragmentMap());
        putAll(CommentClassManager.getInstance().getFragmentMap());
        putAll(CustomerClassManager.getInstance().getFragmentMap());
        putAll(GoodsClassManager.getInstance().getFragmentMap());
        putAll(MajorClassManager.Companion.getInstance().getFragmentMap());
        putAll(OrderClassManager.getInstance().getFragmentMap());
        putAll(PrePurchaseClassManager.getInstance().getFragmentMap());

    }};

    private ClassManager() {

    }

    private static class Instance {
        private static final ClassManager INSTANCE = new ClassManager();
    }

    public static ClassManager getInstance() {
        return Instance.INSTANCE;
    }

    @Override
    public void jump(Context context, Intent intent, String route) {
        if (activityMap.containsKey(route)) {
            intent.setClass(context, Objects.requireNonNull(activityMap.get(route)));
            context.startActivity(intent);
        } else {
            Toast.makeText(context, "目标页面不存在", Toast.LENGTH_SHORT).show();
        }

    }

    @Override
    public void jumpForResult(Activity activity, Intent intent, String route, int requestCode) {
        if (activityMap.containsKey(route)) {
            intent.setClass(activity, Objects.requireNonNull(activityMap.get(route)));
            activity.startActivityForResult(intent, requestCode);
        } else {
            Toast.makeText(activity, "目标页面不存在", Toast.LENGTH_SHORT).show();
        }

    }

    @Override
    public <F extends BaseViewFragment> F showFragment(Context context, FragmentManager fragmentManager, F f, F lastF, int frameLayoutId, String route) {

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        if (f == null && fragmentMap.containsKey(route)) {

            try {
                f = (F) fragmentMap.get(route).newInstance();
                if (lastF != null) {
                    fragmentTransaction.hide(lastF);
                }
                fragmentTransaction.add(frameLayoutId, f).commit();
            } catch (IllegalAccessException e) {
                Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            } catch (InstantiationException e) {
                Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            } catch (Exception e) {
                Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();

                e.printStackTrace();
            }

        } else if (f != null && f.isAdded()) {
            if (lastF != null) {
                fragmentTransaction.hide(lastF);
            }
            fragmentTransaction.show(f).commit();

        } else {
            Toast.makeText(context, "目标页面不存在", Toast.LENGTH_SHORT).show();
        }
        lastF = f;
        return f;
    }

    @Override
    public <F extends BaseViewFragment> F getFragment(String route) {
        try {
            return (F) fragmentMap.get(route).newInstance();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public <F extends BaseViewFragment> F showFragment(Context context, FragmentManager fragmentManager, int frameLayoutId, String route) {

        BaseViewFragment f = null;
        try {
            f = (F) fragmentMap.get(route).newInstance();
            if (f != null && !f.isAdded()) {
                fragmentManager.beginTransaction().add(frameLayoutId, f).commit();
            }
        } catch (IllegalAccessException e) {
            Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        } catch (InstantiationException e) {
            Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        } catch (Exception e) {
            Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }

        return (F) f;
    }

}
在application中注册library中ModuleClassManager中的回调
ModuleClassManager.getInstance().setIClassManager(ClassManager.getInstance());

使用

ModuleClassManager.getInstance().jump(this, Intent(), "major_major_main")

ModuleClassManager.getInstance().showFragment(
        this,
        supportFragmentManager,
        fragment,
        mLastFragment,
        R.id.major_content_fl,
        fragmentKeyMap[itemId]
    )

自此并可以自由于各个子模块之间的调用

Gif_20190523_204114.gif

Gif_20190523_204156.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值