Android开发中陌生的老相识(1)--Android Support Library

好久没有写技术博客了,随着工作中业务的成长的同时,也愈发感受到基础的重要性。有很多我们平时Android开发经常会接触到的事物,由于太过于常见,或者各种开发工具封装的太过完善,导致我们实际上对他们并没有我们想象中的那么熟悉(也就是我说的『陌生的老相识』)。 温故知新,也借此机会刨根问底,打算写一个系列,好好的介绍下这些『老相识』。每篇篇幅不长。第一篇选中的是Android Support库

提一些问题

先提几个问题,看看大家能不能回答上来:

  1. 在已知项目的compileSdkVersion的情况下,Support库的版本号应该设置为多少?大版本号必须相等吗?可以低于或者高于compileSdkVersion吗?
  2. 除了Fragment,ViewPager这些向下兼容的类,你还知道哪些Support库为开发提供了哪些其它功能
  3. 什么时候应该去更新Support库的版本?Support库的接口总是兼容低版本的吗?升级有没有坑?
  4. support库的v4,v7,v8,v13都是什么意思?这些support库都是干什么的?
  5. 如果项目依赖的库自身依赖了support库和app本身依赖的support库版本号不一致,会有冲突吗?如果想排除第三方库本身依赖的support库,该如何做?

嘿嘿,如果对这些问题又有疑惑的话,不妨看看本文。


Support库的用途

按照官方的解释,Support库主要有以下三个用途:

Backward Compatibility for newer APIs (为新API提供向后兼容性)

这个是support最广为认知的用途。support库本身提供了大量的类和方法,为新的SDK新增的功能做支持。类的话如Fragmemt,ViewPager等。方法的话,例如getColor()方法,如果不借助support库的话,需要这么写:

1
2
3
4
5
if (Build.VERSION.SDK_INT >= 23) {
context.getColor(id);
} else {
context.getResources().getColor(id);
}

而借助support库,我们一行搞定,不用再代码里强行嵌入恶心的API判断:

1
ContextCompat.getColor(context, R.color.red);

Convenience and Helper Classes (便利和帮助类)

例如RecyclerView,就是support库为Android开发者提供的列表展示ui组件。

Debugging and Utilities (调试和实用工具)

比如说,MultiDex可以帮助我们应对65536问题。
再例如借助Annotations Support Library,我们可以在代码中注解帮助静态代码分析。举个例子:

1
2
3
4
public static int getValue(Person person) {
//may preduce npe
return person.age;
}
1
2
3
4
5
6
7
public static int getValue(@Nullable Person person) {
if(person == null) {
return -1;
}
//如果没上面的判空,编译器会提醒你这里可能会存在空指针
return person.age;
}
1
2
3
4
public static int getValue(@NonNull Person person) {
// 无需判空,调用的地方,编译器会提示。
return person.age;
}

总而言之,针对使用support库和框架API,官方总结了以下三点差异:

  • Compatibility for a Specific Feature
  • Compatibility for Related Library Features
  • General Device Compatibility

Version Support and Package Names (支持的版本和包名)

展开AndroidStudio的External Libraries,我们可以看到项目中依赖的support库

首先我们知道,support包的包名总是以 『com.android.support』开头,中间是具体的名称,如:support-v4,support-fragment, recyclerview-v7, support-compat等最后跟上版本号

一些包是以#+最低支持的API版本号命名的,如我们熟悉的support-v4包。
从2017年7月开始的26.0.0的Support库,最低支持的版本号是Android 4.0(API 14).所以像
support-v7包和support-v4包。最低支持API都是14.

同时,support包我们知道版本号是a.b.c的格式,例如26.0.2,25.0.1等。其中大版本号也就是与构建库是最新的SDK版本号是一致的。也就是说,26.0。0的support提供了对26及以前版本API的支持(就别希望会提供对27及以后API的支持)

这句话的意思也就是说,假如我们的compileSdkVersion是26,那最好support的library是大于等于26的,26以下的support库没办法保证对26的兼容性。也肯定不会提供27之后才有的新特性。

那我们去哪里找Support库的版本发布历史呢?

Android Support Library Revisions

Support Library Packages (都有哪些Support库)

大的分类来说,目前就有以下这些,种类很多,我们就挑几个最常见的做下介绍:

  • v4 Support Libraries
  • Multidex Support Library
  • v7 Support Libraries
  • v8 Support Library
  • v13 Support Library
  • v14 Preference Support Library
  • v17 Preference Support Library for TV
  • v17 Leanback Library
  • Vector Drawable Library
  • Animated Vector Drawable Library
  • Annotations Support Library
  • Design Support Library
  • Custom Tabs Support Library
  • Percent Support Library
  • ExifInterface Support Library
  • App Recommendation Support Library for TV
  • Wear UI Library

v4 Support Libraries

这个v4大类下的support库平时开发用的非常多,像support-core-utils,support-core-ui,support-fragment等都是最常用的。

Multidex Support Library

支持多dex,不用多解释

v7 Support Libraries

v7包提供了很多对Material Design UI组件的支持,例如Action Bar,cardview,gridlayout,recyclerview等等。

Annotations Support Library

这个注解库非常好用,用的好的可以大幅减少各类调用时的空指针,对lint等静态代码分析都很有帮助。常见的如@Nullable,@NonNull,@IntDef,@StringDef 等都是开发的好助手。前面举了@Nullable,@NonNull的例子,这里举个我们开发中最常见的一类问题,常量参数。

有些时候我们定义了一些type,整形或者字符串格式(定义枚举总是麻烦)例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//定义一些int常量
public static final int TYPE1 = 1;
public static final int TYPE2 = 2;
public static final int TYPE3 = 3;

//这里参数type完全是没有约束的,很可能传不合法的值
public static void func(int type) {
//...
}

//调用方传了个不合法的值,然而这种问题很难被发现
func(-1);

借助Annotations Support Library的@IntDef注解,一切就好多了

```java
@IntDef({
TYPE1, TYPE2, TYPE3
})
public @interface Type {
}
1
2
3
4
//这里参数type有了注解,编译器和lint都会告诉我们传的值是否合法,而且对函数的调用方而言也相当于很好的注释
public static void func(@Type int type) {
//...
}

具体的可以看Android官方文档:

Support Library Packages

问题解答

  • 在已知项目的compileSdkVersion的情况下,Support库的版本号应该设置为多少?大版本号必须相等吗?可以低于或者高于compileSdkVersion吗?

Support Library Version 最好大于等于 compileSdkVersion

  • 除了Fragment,ViewPager这些向下兼容的类,你还知道哪些Support库为开发提供了哪些其它功能

这个前面都说过了。

  • 什么时候应该去更新Support库的版本?Support库的接口总是兼容低版本的吗?升级有没有坑?

一般情况下,Support Library Version和compileSdkVersion大版本保持一致,小版本最新即可。升级compileSdkVersion的时候可以去升级Support Library Version,Support库的接口并不总是兼容低版本的Support库的,而且很多类经常挪动位置,有些类还经常由其它类替换,这个只能升级的时候去摸索了。大部分情况没什么改动。

  • support库的v4,v7,v8,v13都是什么意思?这些support库都是干什么的?

数字通常表示支持的最低API版本号,具体干什么的前面也都有介绍了。

  • 如果项目依赖的库自身依赖了support库和app本身依赖的support库版本号不一致,会有冲突吗?如果想排除第三方库本身依赖的support库,该如何做?

不会有冲突,不同版本号的support库通过可以并存在项目的依赖中,具体可以在Android Studio的External Libraries里面看到,经常会看到好几个版本的support依赖。

如果想排除第三方库本身依赖的support库,gradle依赖可以这么写:

1
2
3
api (xxxxxx) {
exclude group: 'com.android.support'
}

如果只想exludesupport某个具体的包,可以这样写:

1
2
3
api (xxxxxx) {
exclude group: 'com.android.support' ,module: 'support-annotations'
}

参考文档:

Android官方对Support Library的介绍