本篇文章已受权微信公众号 hongyangAndroid (鸿洋)独家发布java
众所周知android提供了不少Support Library做为api的补充,常见的有supprt-v4,v7等,但我发现这些支持库的版本众多,涉及的内容也比较庞杂,本文带你们梳理一下常见的Support Library,而后文章后半部分对一个报错问题展开深究,那就是咱们用开源库时常常碰到的v4重复依赖问题:DexException Multiple dex files define。android
google为啥要弄这么多支持库,直接放到sdk里面很差么? 参阅官方文档有下面3个缘由:设计模式
1.向后兼容 如,咱们开的App须要支持的minSdkVersion=9,targetSdkVersion=11,在程序里使用了android 3.0 (API level 11)提供的ActionBar类,使用compileSdkVersion=11成功编译出apk。在android 3.0的设备上完美运行,可是app在android 2.3的设备就会crash,报找不到ActionBar的错误。这很好理解,由于旧版本上没有新版本里新增的类。为了不使用了最新功能开发的app只能在最新系统的设备上运行的尴尬,官方把新版系统framework中新增长的接口提出来放到了Android Support Library(支持包)中,开发者在遇到上面的状况时,就可使用支持包中具备一样功能的ActionBar类,这个支持包会打包进App里,这样使用了新版本系统上功能的App也能够向后兼容之前的老系统版本设备了。 使用支持包中的类除了让咱们免于判断App运行的系统版本外,还可使App在各个版本保持一样的用户体验。如在5.0如下系统使用material design。api
2.提供不适合打包进framework的功能微信
Android官方对App开发提供了推荐设计,但愿Android应用都有相对一致的交互设计来减小用户的使用成本,但愿三方App相似系统应用从而完美融入到Android生态系统中。可是这都仅仅是推荐,不要求开发者必定要这样,若是有这种需求就可使用官方支持包提供的这些功能,避免重复造轮子。如支持包中的DrawerLayout、Snackbar等类都是这种状况。app
3.为了支持不一样形态的设备框架
经过使用支持包来在不一样形态设备上提供功能,如手机、电视、可穿戴设备等。maven
Android 支持库提供了诸多未内置于框架的功能。这些库提供向后兼容版本的新功能、框架中未包含的实用 UI 元素,以及应用能够利用的一系列实用程序。好比ide
Material Design是Android 5.0加入的新功能,可是不少设备依然装的是Android4.0系统,若是为了Material Design将minSdkVersion设置为 api21显然不合理的,那为了Android5.0如下的设备可使用Material Design的效果,就应该使用support-library,包括以前的Fragment和如今的权限检查,都是这个原理!工具
目前为止Android Support Library包含的依赖包有:比较经常使用的是1,2,3
v4名称是最开始支持api level4的库,官方在Support Library 24.2.0版本的时候移除了对Android 2.2(API Level 8)及如下版本的支持,因此从Android Support Library 24.2.0开始,V4包支持的最低版本是Android 2.3即API Level 9),而且把v4库拆分红5个部分,能够在项目中按须要引用,可是必要性不是很大,一是由于这5个部分有依赖关系,二是compat库占了v4库的一半大小,v4库的依赖关系图:
好比下面这些都是v4包的内容: Fragment:一个专为解决Android碎片化的类,经过它可让同一个程序适配不一样的屏幕。 NotificationCompat:支持更丰富的通知形式; LocalBroadcastManager:适合于应用内的消息传递。 ViewPager:一个能够管理子view的viewgroup,用户能够在各个view之间自由切换,这个在不少应用中都有使用到;
上面说到v4是兼容level9以前的版本,那若是咱们的compileSdkVersion>9是否是能够不用v4了? 这个不必定的,好比ViewPager这个类只在V4包中才有,在sdk中没有。
compile 'com.android.support:support-v4:21.0.3'
复制代码
同步gradle以后,在ExternalLibrarys右键v4选择:library propertity查看依赖库的信息:
V7和V4同样,一样包含多个依赖包,但和V4不一样的是,V7下的多个子包并非后面拆分开来的,而是最初发布时就以各个独立库的形式发布的。它是针对Android 2.3(API Level 9)及以上的版本谷歌提供了一系列的support包(和V4包的命名同样,V7最初支持的最低版本是Android 2.1即API Level 7,因此称其为V7,一样在Android Support Library 24.2.0将V7支持的最低版本改成Android 2.3即API Level 9了),这些support包各自对应着特定的功能,每个均可以单独地被引用。
v7 app-compat这个包支持对Action Bar接口的设计模式、Material Design接口的实现等,核心类有ActionBar、AppCompatActivity、AppCompatDialog、ShareActionProvider等
compile 'com.android.support:appcompat-v7:24.2.1'
复制代码
用这个maven方式配置v7会自动引入v4库,so不须要再额外引入v4库了。 gradle中jar依赖语句格式如 compile 'jar文件组(group/命名空间):jar文件名(name):jar文件版本(version)'。因此上面的语句意思是依赖Android支持库中第24.2.1版的appcompat-v7库。
当你的项目代码量愈来愈大的时候,会发现某一天运行在Android5.0如下的手机莫名崩溃。报错:某个类class not found,而这个类明明就有啊。。。其实这就是 著名的方法数超过 64K 的应用异常。解决办法就是这个支持库。
android {
defaultConfig {
...
minSdkVersion 15
targetSdkVersion 26
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
复制代码
而后在自定义的Application的加入:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
复制代码
下面详细介绍 很常见的v4库的重复依赖问题,先抛出两个问题:
为啥问这个问题,源于我看网上不少文章,介绍v4的时候不假思索地下结论:v7包含v4!真的是这样吗???
咱们打开v7的jar包看源码,其实appcompat-v7包自己是不包含v4的jar包的:
新建一个工程,加入v7的依赖包:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:24.2.1' } 复制代码
看下项目目前的依赖包状况:
果真,项目自动引入了v4下面的全部包,v7包涵v4的意思是:
compile 'com.android.support:appcompat-v7:24.2.1', gradle会自动加入全部v4包的依赖,而且是和v7相同的版本
不是必须的。只是官方建议保持一致,若是版本不一致仍然能够编译运行。
上面已经证实依赖v7包会自动引入v4包,那么在项目中同时依赖v4和v7,会出现所谓的重复依赖编译报错吗?
能够成功编译运行安装,没有报错:
:mylibrary:preDebugUnitTestBuild UP-TO-DATE
:mylibrary:prepareDebugUnitTestDependencies
BUILD SUCCESSFUL
Total time: 7.005 secs
复制代码
即便同时引入不一样版本的v4包,也并无出现包依赖重复的报错,能够正常编译运行:(注:红线是版本和compileSdkVersion不一致致使,此处忽略)
确实引入了不一样版本的v4包:
接下来,试试maven引入21.0.3的v4包,而后本地引入19.1.0的jar包:
运行时报错: dex文件冲突
固然,若是lib放入的和maven配置v4包版本21.0.3相同,是能够的。
(Android从support-20.0.0版本开始,v4的jar包所有升级为aar包),解压工具提取aar里面的classes.jar而后重命名为support-v4-21.0.3.jar放入lib文件夹
一个项目每每要引入不少开源库,试图统一全部moduler的v4版本是不现实的,只能经过exclude 方法过滤某些库的v4包,保证整个项目只引入一个版本。
1. 首先查看当前项目各类库的依赖状况:
2. 找到里面版本冲突的依赖库,而后查找app项目,开源库的lib目录,删除对应的jar包改用maven形式引入。
3. 若是你的app必需要使用本地lib引入v4库,那么就排除开源库的v4包:
compile('com.facebook.fresco:fresco:0.10.0') {
exclude module: 'support-v4'
}
复制代码
若是是源码形式引入的开源库:
compile (project(':thirdpart:RecyclerViewAdapterLibrary')){
exclude group: 'com.android.support'
}
复制代码