我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情
组件化开发系列文章
1. Android组件化开发之一:为什么要进行组件化开发
2. Android组件化开发之二:组件化架构
3. Android组件化开发之三:组件化开发手册
4. Android组件化开发之四:组件化填坑之旅
5. Android组件化开发之五:组件化开发实战Demo
序号
名称
坑深度
内容
1JPush
极光推送的配置文件不能放在library工程里面,必须放到application工程中。2Resource IDs
Resource IDs cannot be used in a switch statement in Android library modules.
Android Studio里面快捷转换方式:选中“switch”,ALt+Enter同时选中,弹出对话框,选择“Replace 'switch' with 'if'”。
3ButterKnife引用
在library工程中,提示:Attribute value must be constant。
这是因为library中R.id.xxx 取R中变量的时候并非是final类型。
解决方法:
ButterKnife在8.0版本以上支持library内使用视图注入,原先app用的是7.x版本的,所以要先升级到8.x版本。
期间还需要将以前的R用R2代替。
有时候AS识别不了R2,需要多build几次。
4ButterKnife点击
接上所述,正常情况下,Butterknife的点击事件是这样的:
@OnClick({R2.id.btn_login, R2.id.btn_regist})public void onClick(View view) { int i = view.getId();if (i == R2.id.btn_login) {......
但现在的问题是,view.getId()获得的是R类中的id,而不是R2类中的id,特么的巨坑!!!
解决方法:
1、使用RCaster类做一个R到R2的转换。
2、不用ButterKnife响应click事件,就用android原生的onClick。
5Dagger2
Dagger2在各个组件工程里面有时候不会生成对应的文件,有时候生成了文件AS不能立刻识别,要等一段时间,可能这是dagger2和AS之间的bug吧。
解决方法:
第一步、在build-generated-source-apt-release下找到对应的daggerXXXX文件,然后双击打开。
第二步、点击Build–Make Module XXXX。
第三步、等一会AS就能识别出来。
6annotationProcessor
apt已经停止更新,需要全面切换到annotationProcessor,以防止不必要的坑。7versionName、versionCode
application项目里面必须得有这两个属性。8拆分
建议从原有工程中逐步将功能拆分至各个组件项目,而不是另起一个全新项目。9Service
service必须放到application项目中,不能放到library项目中,必须注意!!!10BuildConfig
application工程对library工程的依赖都是release依赖!!!
所以一些根据debug和release来判断的操作,需要放到application工程里面。
还有一种解决方案:publishNonDefault true
参考 http://www.jianshu.com/p/64f57439934b
11So文件
各个工程的libs里面的so文件,需要在各个工程的build.gradle文件中用如下方式引入,不然打包的时候so文件包含不进去:
sourceSets { main { jniLibs.srcDirs = ['libs'] }}12
AsyncTask
asynctask在组件间调用的时候会出现AsyncTask java.lang.ClassCastException: java.lang.Object[] cannot be cast to java.lang.Void[] 异常。
解决方案:
1、去掉泛型;
2、泛型将Void类型换成非Void类型。
13ApplicationId
applicaitonId和packageName的区别:
1、如果没有applicationId,则以packageName的值为应用包名;
2、如果有applicationId,则以applicationId的值为应用包名;
应用案例:
Module模块中,如果需要使用到极光推送的,而极光推送跟包名又是强相关的,
可以利用applicationId进行包名控制,而不需要去改动packageName。
14JPush
目前项目使用的JPush版本还是1.7.0。
在module作为单个apk独立运行时,会出现如下情况:
提示:
[AndroidUtil] The permissoin is required - android.permission.WRITE_SETTINGS
[AndroidUtil] You should make main activity extends InstrumentedActivity (JPush), otherwise you will not see user click and user active time start on report in Portal.
有两种情况:
(一)原因是这个版本在android api为23及以上使用时,不能够权限更改做判断;
目前解决方案是将targetSdkVersion设为21及以下。
但是在app壳工程里面targetSdkVersion设为23是可以的。
(二)原因是app没有签名。
在buildTypes里面要加上:signingConfig signingConfigs.debugConfig
15Instant Run
在Android Studio 2.3.3和Gradle 3.3环境下面,开启instant run后,整个项目的编译和单个组件的编译会异常耗时,而且会出现处理R.class时crash现象;
所以在平时调测过程中,需要将instant run关闭后编译。
16编码问题
org.gradle.jvmargs = -Dfile.encoding=UTF-8
如果jvmargs的设置如上,则会出现项目中png图片不能识别问题:
AAPT err(Facade for 169869688) : No Delegate set : lost message:\?xxxbase-corebuildintermediatesbundlesdefaultresdrawable-xhdpi-v4query_loding5.png ERROR: Unable to open PNG file
17resourcePrefix
设置了resourcePrefix值后,所有的资源名必须以指定的字符串做前缀,否则会报错。
但是resourcePrefix这个值只能限定xml里面的资源,并不能限定图片资源,所有图片资源仍然需要手动去修改资源名。
引用aar
在Android Studio中创建一个module或者导入一个module的时候,如果这个module中依赖了aar库,当build工程的时候,会出现failed to resolve这个错误。
需要在引用这个module之前的每一个module或app的build.gradle里面,添加如下代码:
repositories { flatDir { dirs project(':你的module名称').file('libs') } }
19
手动替换aar
需要关闭android studio然后重新打开,不然死活识别不出来。20Multiple dex files define Lcom/xx/xx/BuildConfig解决方法一:找到引用的aar包,用压缩软件打开,把里面的BuidConfig给删了,然后引用删除后的包
解决方法二:在library工程的build.gradle中的android范围内加入:packageBuildConfig(false)
21使用ButterKnife后的混淆由于使用了R2这个资源文件,所以在混淆的时候需要增加排除对R2的混淆,如下:
-keep class **.R$* {*;}-keep class **.R2$* {*;} 22找不到资源文件:NoSuchFieldError开发的时候,通过 Ctrl+右键 能够正确找到相应的ResId,但是一旦运行起来,无论是通过ButterKnife还是findViewById都会报此错。此种情况需要检查是否module的layout命名与其他module有冲突,重命名layout文件名称后即可解决。
建议在不同的module之间配置 gradle:resourcePrefix "xxx_" 加以区分格式
23ButterKnifemodule工程里面必须引用 annotationProcessor 'com.jakewharton:butterknife-compiler:8.x.x'不然会出现控件绑定失效,导致OnClick等这样的事件无法实现
24APP+Library
+productFlavors+buildTypes
好处:library工程根据app工程传过来的参数进行个性化配置,比如测试环境or正式环境。
详情参加:http://blog.csdn.net/wenyiqingnianiii/article/details/70183816
打包注意:
developCompile project(path: ':library', configuration: 'developDebug')1、这样的打包形式,以在app工程的build.gradle脚本为例:
developCompile的develop表示app的Flavors;configuration的developDebug表示library工程的flavors是develop,buildTypes是debug;
所以在library中必须有对应的flavors。
2、app工程向library工程传值
(1)library可以通过libraryVariants.all、variant.buildType.name、variant.flavorName来判断由app传入的值是什么,从而进行个性化处理。
(2)当然,library还可以通过直接在buildTypes、productFlavors脚本里面编写代码进行个性化处理。注:publishNonDefault true
(3)app工程初始化的时候,可以调用library工程的类进行初始化设定。
3、打包的时候,左下角的Build Variants选择Build Variant的时候,需要对应app脚本中xxxCompile的信息。
如按照上述脚本,应该选择app:developDebug,library:developDebug。
同样,在右上角的Gradle脚本里面,也要选择对应的脚本名称,比如这个脚本的名称为:assembleDevelopDebug。
25library二次引用注:一定要以maven的形式compile进来;如果library工程有jar包,app工程要把重复的jar包去掉。
1、比如A工程引用了B库,B库引用了C库,如果A工程引用了C库,那么C库知会被引用一次,并且是最新版本的。
如果B库引用的C库是1.0版本,而A工程引用的C库是1.1版本,那么在A工程里面知会引入C库的1.1版本。
所以不用担心C工程二次引用重复的问题。但如果是jar包则不行。
2、可以用+号表示永远引用最新版本的库工程,比如compile 'com.midea.smart.lib:lib-ui:+',但不建议这样引用。推荐写成固定的版本。
原因:
每次build时会向网络进行检查,国内访问仓库速度很慢;
库更新后可能会更改内部逻辑而带来bug,动态版本无法通过git的diff来规避此问题;
每个开发者都可能会得到不同的最新版本,带来潜在隐患。
3、比如A工程引用了B库,B库引用了C库,如果A工程引用了C库,但是B库引用的C库groupId不一样,
这样会造成的结果就是,A工程知会引入B库所引用的C库的版本,比如B库引用的C库的版本是2.0,而app工程引用的C库的版本是2.1,
这样的情况下,app工程只会引入2.0版本的C库,这是一个坑,不过也不是经常遇到。
26Android Studio引用版本号
android studio的坑,compile的版本号如果以前引用过的话,后面修改后,如果保持版本号不变,android studio再次引用进来会导致一些莫名其妙的问题。
解决方案:
按照maven的版本管理规范,后续将maven上面的版本正式管理起来,有变更时版本号往上增加:
1、平时开发版本放到snapshot上面;
2、release只用来上传正式发布版本。
工程编译速度慢,主要跟以下两种情况有关,我们可以针对性地做出一些优化措施:
1、Flavors+BuildType组合,编译出来的library工程的aar包很多,导致编译速度慢;
解决措施:确定library是否需要flavors和buildtype,如果不需要,就可以不用用这种组合编译方式编译,可以只选择一个。
2、settings.gradle中包含的library工程太多,这个影响是致命的。
解决措施:将library工程的aar包,放到app工程的libs里面,在app里面引用aar。
29错误: 找不到符号app工程引用library工程的时候,有时候会发现“错误: 找不到符号”这个错误,但是跳转到代码处有没有报错。
实际上这个原因是因为library工程中将混淆开启了,所以需要将library的minifyEnabled设置为false!不能用混淆!