欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android组件化+Arouter通讯解析

程序员文章站 2022-05-14 10:34:18
android化+arouter通讯解析。 实际开发中越是大型的项目,代码量越多,而androidstudio编译的速度越慢。除了抬高电脑配置外,如何提高程序员的开发效率越是迫在眉睫。除此之外,团队...

android化+arouter通讯解析。

实际开发中越是大型的项目,代码量越多,而androidstudio编译的速度越慢。除了抬高电脑配置外,如何提高程序员的开发效率越是迫在眉睫。除此之外,团队合作开发,合并代码也是一个头疼的问题。虽然可以使用svn/git来规避一些问题,但团队中一个人的代码出了问题,导致自己也是*停止开发也是可能的。

组件化:

项目代码臃肿的时候,通常考虑拆分代码,分层的方式。组件化是将项目按照业务拆分成一个个组件,进而达到解耦分层。一个组件化必须能够单独调试,集成编译,数据传输,ui转跳,生命周期,代码边界这六大特征。

通过一个组件化模型来进一步了解:

Android组件化+Arouter通讯解析

通过上图可知:

空壳app : 负责管理各个业务组件,和打包apk,没有具体的业务功能; main组件 :属于业务组件,指定app启动页面、主界面 movie组件 :属于业务组件,用于显示电影列表 collection组件 : 属于业务组件,用于显示收藏的电影列表 commonlibrary(基类库) : 属于功能组件,提供业务组件需要的通用的功能,例如:网络请求,图片加载,mvp框架,工具类,每个组件的数据实体等等。

1.先配置依赖库和版本号统一的管理

工欲善其事必先利其器,不能因配置问题导致开发拖延,因此先配置好需要的各种库。

本项目使用到以下库

android 官方的常见库 rxjava和rxandroid 异步操作库 retrofit,okhtttp 网络库 glide 图片加载库 sqlbrite轻量级数据操作库 arouter路由通讯库

先创建一个config.gradle,编写以下代码:

// 第三方库,app的版本号的管理和组件模式的切换配置
ext{
    isalone=false; //false:作为lib集成存在, true:作为application组件存在

    android = [
            compilesdkversion : 27,
            minsdkversion :15,
            targetsdkversion :27,
            versioncode :1,
            versionname :"1.0",
    ]
    libsversion=[
            // app dependencies version
            supportlibraryversion = "27.0.2",
            support_v4 = "27.0.2",
            arouter_api = "1.3.1",
            arouter_compiler = "1.1.4",
            sqlbrite="1.1.1",
            rxjava="1.3.0",
            rxandroid="1.2.1",
            retrofit="2.3.0",
            converter_gson="2.3.0",
            adapter_rxjava="2.3.0",
            okhttp="3.8.0",
            logging_interceptor="3.8.0",
            glide="3.8.0",
    ]
    dependencies = [
            //android 官方库
            appcompatv7               : "com.android.support:appcompat-v7:$rootproject.supportlibraryversion",
            support_v4                : "com.android.support:support-v4:$rootproject.support_v4",
            design                     : "com.android.support:design:$rootproject.supportlibraryversion",
            cardview                   : "com.android.support:cardview-v7:$rootproject.supportlibraryversion",
            palette                    : "com.android.support:palette-v7:$rootproject.supportlibraryversion",
            recycleview               : "com.android.support:recyclerview-v7:$rootproject.supportlibraryversion",
            annotations               : "com.android.support:support-annotations:$rootproject.supportlibraryversion",
            //路由通讯
            arouter_api                : "com.alibaba:arouter-api:$rootproject.arouter_api",
            arouter_compiler          : "com.alibaba:arouter-compiler:$rootproject.arouter_compiler",
            // sqlbrite
            sqlbrite :"com.squareup.sqlbrite:sqlbrite:$rootproject.sqlbrite",
            //rxjava
            rxjava                      :"io.reactivex:rxjava:$rootproject.rxjava",
            rxandroid                  :"io.reactivex:rxandroid:$rootproject.rxandroid",
            // okhttp
            okhttp                     :"com.squareup.okhttp3:okhttp:$rootproject.okhttp",
            logging_interceptor       :"com.squareup.okhttp3:logging-interceptor:$rootproject.logging_interceptor",
            //retrofit
            retrofit                   :"com.squareup.retrofit2:retrofit:$rootproject.retrofit",
            converter_gson            :"com.squareup.retrofit2:converter-gson:$rootproject.converter_gson",
            adapter_rxjava            :"com.squareup.retrofit2:adapter-rxjava:$rootproject.adapter_rxjava",
            //glide
            glide                     :"com.github.bumptech.glide:glide:$rootproject.glide",
    ]
}

接下来,在project的build.gradle中添加以下代码,进行配置引用。

apply from:"config.gradle"

在每一个module组件中,进行依赖。

先在commonlibrary基类库中builde.gradle进行依赖:

apply plugin: 'com.android.library'
android {
    compilesdkversion rootproject.ext.android.compilesdkversion

    defaultconfig {
        minsdkversion rootproject.ext.android.minsdkversion
        targetsdkversion rootproject.ext.android.targetsdkversion
        versioncode rootproject.ext.android.versioncode
        versionname rootproject.ext.android.versionname
        javacompileoptions {
            annotationprocessoroptions {
                arguments = [modulename: project.getname()]
            }
        }
    }
}
dependencies {
    implementation filetree(include: ['*.jar'], dir: 'libs')
    //android support ,任何一个module依赖的官方包都在这里配置
    api(rootproject.ext.dependencies.appcompatv7) {
        exclude module: "support-annotations"
        exclude module: "support-v4"
    }
    api(rootproject.ext.dependencies.support_v4) {
        exclude module: "support-annotations"
    }
    api rootproject.ext.dependencies.recycleview
    api rootproject.ext.dependencies.design
    api rootproject.ext.dependencies.annotations
    // arouter 依赖
    api rootproject.ext.dependencies.arouter_api
    //rxjava
    api(rootproject.ext.dependencies.rxjava) {
        exclude module: "rxandroid"
    }
    api rootproject.ext.dependencies.rxandroid
    //sqlbrite
    api rootproject.ext.dependencies.sqlbrite
    //retrofit
    api rootproject.ext.dependencies.retrofit
    api rootproject.ext.dependencies.converter_gson
    api rootproject.ext.dependencies.adapter_rxjava
    // okhttp
    api rootproject.ext.dependencies.okhttp
    api rootproject.ext.dependencies.logging_interceptor
    //glide
    api rootproject.ext.dependencies.glide
}

最后,每一个业务组件(例如:movie组件和collection组件)的build.gradle依赖:

android {
    compilesdkversion rootproject.ext.android.compilesdkversion
    defaultconfig {
        minsdkversion  rootproject.ext.android.minsdkversion
        targetsdkversion rootproject.ext.android.targetsdkversion
        versioncode rootproject.ext.android.versioncode
        versionname rootproject.ext.android.versionname

        testinstrumentationrunner "android.support.test.runner.androidjunitrunner"
        if (rootproject.ext.isalone) {
            //   组件模式下设置applicationid
            applicationid "com.xingen.collection"
        }
        javacompileoptions {
                annotationprocessoroptions {
                    arguments = [modulename: project.getname()]
                }
        }
    }
}

dependencies {
    implementation project(':commonlibrary')
    //集成模式下需要编译器生成路由通信的代码
    annotationprocessor rootproject.ext.dependencies.arouter_compiler
}

整个项目的结构,如下所示:
Android组件化+Arouter通讯解析

2. 编写commonlibrary基类库

将每个业务组件需要用到的通用操作都封装到一个通用的commonlibrary基类库中,然后直接在每个业务组件中依赖该库。
如下图所示,将一些常见的操作,实体类,网络操作,图片加载,mvp架构等等。 除此之外,统一的style风格,权限也应该定义在commonlibrary中。

Android组件化+Arouter通讯解析

除此之外,每个组件的application问题。如何获取每个组件的通用application?

写一个超类baseapplication,将一些常见初始化操作放到里面.

public class baseapplication  extends application {
    private static  baseapplication instance;
    @override
    public void oncreate() {
        super.oncreate();
        instance=this;
        initrouter();
    }
    public static baseapplication getinstance(){
        return instance;
    }
    private void initrouter(){
        if (buildconfig.debug) {
            //一定要在arouter.init之前调用opendebug
            arouter.opendebug();
            arouter.openlog();
        }
        arouter.init(this);
    }
}

写一个工具类,让每个组件可以获取到这个baseapplication。

public class contextutils {
    public static baseapplication getappcontext(){
        return baseapplication.getinstance();
    }
}

然后让每个组件的application去继承这个baseapplication。以movie组件为例。

public class movielistapplication extends baseapplication{
    @override
    public void oncreate() {
        super.oncreate();
    }
}

最后在组件的androidmanifest.xml中去引用该定义的movielistapplication。

3. 集成和组件模式的切换

组件化具备每个组件单独调试和集成的特点。

在config.gradle中设置一个标志,便于切换。

ext{
    isalone=false; //false:作为lib集成存在, true:作为application组件存在
}

组件的组件模式是指单独调试的application项目,集成模式是指library项目,依赖到空壳app中。

这里以movie组件为案例,来介绍,在其build.gradle中。

//控制组件模式和集成模式
if (rootproject.ext.isalone) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
android {
      defaultconfig {
        if (rootproject.ext.isalone) {
            //   组件模式下设置applicationid
            applicationid "com.xingen.movie"
        }
      }
}

每次切换模式,androidstudio需要sync 下,在运行对应的项目。

4. 一些常见问题处理

4.1 组件在集成模式和组件模式下的代码和androidmanifest.xml

在组件模式下,需要单独调试,具备mainactivity和applciation类。

这里以movie组件为例,在java文件夹下创建一个debug文件夹,放入对应mainactivity和applciation类。

在main文件夹下创建一个module文件夹,放入组件模式下的androidmanifest.xml。




    
        
            
                

                
            
        
    

而集成模式下的androidmanifext.xml,不能有application和主的activity,不能声明app名称、图标等属性。


    
    
        
    

最后在gradle配置,*切换集成模式和组件模式下的不同代码。

android {
    sourcesets {
        main {
            //控制两种模式下的资源和代码配置情况
            if (rootproject.ext.isalone) {
                manifest.srcfile 'src/main/module/androidmanifest.xml'
            } else {
                manifest.srcfile 'src/main/androidmanifest.xml'
                //集成开发模式下排除debug文件夹中的所有java文件
                java {
                    exclude 'debug/**'
                }
            }
        }
    }

}

最终,movie组件项目的结构,如下所示:

Android组件化+Arouter通讯解析

4.2 资源命名冲突

若是多个组件项目中都具备相同名字的图标,那么集成打包app会报错。

最好的解决方式:就是每个组件的资源文件(图片,xml)都约定好以什么组件名为前缀。

4.3 library依赖问题

第三方依赖库可能到引入重复包问题,通过exclude module去除指定重复包,具体详情查看1.先配置依赖库和版本号统一的管理。

5. 阿里arouter通讯

模块之间的通讯通过arouter来实现。

例如,main模块中要获取到movie模块中的一个fragment类,但两个模块又不能直接依赖。通过arouter的暴露服务来通讯可以解决。

先在commonlibraray中定义一个iprovider子类,定义一个服务.

public interface movielistprovider extends iprovider {
    fragment createfragment();
}

定义该服务的路径:

public final class routerpath {
    /**
     * 电影列表的路径
     */
   public static  final  string path_movie_list="/movieservice/movie_list";
}

然后在movie组件中,实现该服务。

@route(path = routerpath.path_movie_list)
public class movielistproviderimpl implements movielistprovider {
    @override
    public fragment createfragment() {
        movielistfragment fragment=movielistfragment.newinstance();
        movielistpresenter presenter=new movielistpresenter(fragment, netclient.getinstance(), sqlclient.getinstance());
        return fragment;
    }
    @override
    public void init(context context) {

    }
}

最后在main组件中获取该服务对象,从而获取到movie组件中的fragment。

public class mainactivity extends baseactivity implements navigationview.onnavigationitemselectedlistener {
    @autowired
    movielistprovider movielistprovider;

    @override
    public void init(bundle savedinstancestate) 
        arouter.getinstance().inject(this);

        fragment fragment = movielistprovider.createfragment();
        getsupportfragmentmanager().begintransaction().add(r.id.movielist_content_layout, fragment).commit();
    }

}

当然,还有很多关于arouter的用法,请点击查看arouter文档。

6. 运行效果

单独movie组件效果:

Android组件化+Arouter通讯解析