阅读 946

【Android组件化】 组件化编程

组件间的通信机制

组件化急需解决的问题就是组件间的通信问题。

EventBus 事件总线

事件总线机制通过记录对象,使用监听者模式来通知对象各种事件。

EventBus的主要功能是替代Intent,Handler,BroadCast,在Fragment,Activity,Service和线程之间传递消息。实现发送者和接收者解耦。订阅者可以订阅多个事件,发送者可以发布任何事件,同时也可以是订阅者。还可以设置事件处理线程和优先级。

ARouter 路由跳转

组件化开发中,可以将各个 module 当作不同的网络,路由器就是连接各个网络的中转站,可以拦截跳转或者设置特定的拦截器。路由跳转无需依赖类,无需在AndroidManifest.xml中注册,适合于组件化解耦。

greenDAO 数据库存储

greenDAO是一个ORM框架,能够提供一个接口,通过操作对象的方式操作关系型数据库。greenDAO的原理是将对象转化为一项数据,实现对象到关系数据库的映射。

AndPermission 权限管理

AndPermission对于国内手机的适配较好。具体可以访问对应的GitHub。可以将AndPermission和ARouter结合,在跳转之前进行权限的校验。

R.java 资源限制

R.java文件是 aapt 打包资源文件时生成的。

组件 module 中的静态变量并没有被赋予final属性。对应文件位置为:/build/generated/source/r/debug/包名/R.java。

可以看到每个资源文件在R中都是一个class,每个资源项名称都分配了一个id,id值是一个四字节无符号整数,格式是这样的:0xpptteeee,(p代表的是package,t代表的是type,e代表的是entry),最高字节代表Package ID,次高字节代表Type ID,后面两个字节代表Entry ID。

Package ID相当于是一个命名空间,限定资源的来源。Android系统当前定义了两个资源命令空间,其中一个系统资源命令空间,它的Package ID等于0x01,另外一个是应用程序资源命令空间,它的Package ID等于0x7f。所有位于[0x01, 0x7f]之间的Package ID都是合法的,而在这个范围之外的都是非法的Package ID。

Type ID是指资源的类型ID。资源的类型有animator、anim、color、drawable、layout、menu、raw、string和xml等等若干种,每一种都会被赋予一个ID。

Entry ID是指每一个资源在其所属的资源类型中所出现的次序。注意,不同类型的资源的Entry ID有可能是相同的,但是由于它们的类型不同,我们仍然可以通过其资源ID来区别开来。

各个 module 会生成.aar文件,并且被引用到 app module中,最终合并为apk文件。当各个 module 被解压到 app module 时,R.java中的id属性会被添加声明为final属性。对应文件位置为:/build/generated/source/r/debug/包名/R.java

当各个组件 module 被汇总到 app module时,也就是编译初期解析资源阶段,会检测所有的R.java文件,然后通过合并,最终生成唯一的一份R.java资源文件。

由于组件 module 中的R.java没有final关键字修饰id,所以在必须使用常量的地方都不能使用R.java中的变量。包括注解和switch语法等。

每个组件 module各自生成aar文件的时候,aapt会单独生成R.java文件,然后在app module中执行java compile命令编译class文件时会将常量变化成具体的值。

ButterKnife使用替换的方法,原理是将R.java文件复制一份,命名为R2.java,然后再R2.java中为所有变量加上final修饰符,在相关的地方使用R2资源。

资源冲突

组件化中,被依赖的 module 会被编译成aar文件,然后解压到依赖的 module中,最终汇集到 app module中。此时会通过gradle的机制防止出现重复的aar文件。不添加重复的库资源到编译中。我们有时候会遇到在被依赖的库中出现两个重复的库,此时默认会使用版本较高的依赖。若果想使用版本较低的依赖,可以使用exclude方式排除。

对于资源名重复的情况,会出现资源引用出错的情况。后编译的模块会覆盖之前编译的模块的资源字段的内容。

混淆

Android Studio使用ProGuard进行混淆,可以压缩,优化和混淆Java字节码文件,压缩和优化体现在可以删除无用的类,字段,方法,属性和注解,还可以删除无用的注解,优化字节码文件。还可以使用简短无意义的名称来重命名已经存在的类,字段,方法和属性。

minifyEnabled true:打开混淆

shrinkResource true:打开资源压缩

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro':设置proguard文件的路径

混淆之后为了根据出错的信息找回原本出错的地方可以到对应文件下找对应的文件:/build/outputs/mapping/client/release/

dump.txt:包含目录内所有class文件的结构 mapping.txt:记录混淆后路径和原路径的映射关系。 resources.txt:记录资源文件信息。 seeds.txt:未混淆的类和成员,验证是否持有不想混淆的类。 usage.txt:累出apk被删除的代码。

微信用来提供混淆机制。

在每个module创建之后都会有自己的proguard文件,每个proguard文件可以有自己的混淆规则。如果每个module都使用自己的混淆规则就会造成重复混淆,造成定位不到源文件的问题。可以在app module中设置所有混淆操作来避免。

多渠道打包

Android Studio提供了多渠道模块配置

productFlavors属性用于设置不同的渠道

manifestPlaceholders属性用于设置不同渠道中的不同属性,这些属性需要在AndroidManifest.xml文件中声明才能使用。

设置xxxCompile用来配置不同渠道需要引用的module文件。

    /**
     * 获取meta-data值
     * @param context
     * @param metatName  key名
     * @return
     */
    public static Object getMetaData(Context context, String metatName){
        Object obj= null;
        try {
            if (context !=null){
                String pkgName = context.getPackageName();
                ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(pkgName, PackageManager.GET_META_DATA);
                obj = appInfo.metaData.get(metatName);
            }
        }catch (Exception e){
            Log.e("AppMetaUtil",e.toString());
        }finally {
            return obj;
        }
    }

    /**
     * 获取渠道号
     * @param context
     * @return
     */
    public static int getChannelNum(Context context){
        if (channelNum <= 0){
            Object obj = AppMetaUtil.getMetaData(context,"channel");
            if (obj!=null && obj instanceof Integer){
                return (int)obj;
            }
        }
        return channelNum;
    }

    /**
     * 获取设置信息类路径
     * @param context
     * @return
     */
    public static String getSettingInfo(Context context){
        if (settingInfo ==null){
            Object obj = AppMetaUtil.getMetaData(context,"setting_info");
            if (obj!=null && obj instanceof Integer){
                return (String)obj;
            }
        }
        return settingInfo;
    }
复制代码
文章分类
Android