前几天 Google 官方发布文章解析 compileSdkVersion、minSdkVersion 以及 targetSdkVersion 的含义,以及合理设置各个值的意义,原文 Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion(后面简称 “原文”),还有翻译版

其中,compileSdkVersion 和 minSdkVersion 都非常好理解,前者表示编译的 SDK 版本,后者表示应用兼容的最低 SDK 版本。但是对于 targetSdkVersion 其实很难一句话解析清楚,原文用了“万能”的词 —— interesting 来描述。以前我也有一些迷糊,看到有些人和我有同样的困惑,本文试图彻底解决这个问题。

原文是这么说的:

targetSdkVersion is the main way Android provides forward compatibility

targetSdkVersion 是 Android 系统提供前向兼容的主要手段。这是什么意思呢?随着 Android 系统的升级,某个系统的 API 或者模块的行为可能会发生改变,但是为了保证老 APK 的行为还是和以前兼容。只要 APK 的 targetSdkVersion 不变,即使这个 APK 安装在新 Android 系统上,其行为还是保持老的系统上的行为,这样就保证了系统对老应用的前向兼容性。

这里还是用原文的例子,在 Android 4.4 (API 19)以后,AlarmManager 的 set() 和 setRepeat() 这两个 API 的行为发生了变化。在 Android 4.4 以前,这两个 API 设置的都是精确的时间,系统能保证在 API 设置的时间点上唤醒 Alarm。因为省电原因 Android 4.4 系统实现了 AlarmManager 的对齐唤醒,这两个 API 设置唤醒的时间,系统都对待成不精确的时间,系统只能保证在你设置的时间点之后某个时间唤醒。

这时,虽然 API 没有任何变化,但是实际上 API 的行为却发生了变化,如果老的 APK 中使用了此 API,并且在应用中的行为非常依赖 AlarmManager 在精确的时间唤醒,例如闹钟应用。如果 Android 系统不能保证兼容,老的 APK 安装在新的系统上,就会出现问题。

Android 系统是怎么保证这种兼容性的呢?这时候 targetSdkVersion 就起作用了。APK 在调用系统 AlarmManager 的 set() 或者 setRepeat() 的时候,系统首先会查一下调用的 APK 的 targetSdkVersion 信息,如果小于 19,就还是按照老的行为,即精确设置唤醒时间,否者执行新的行为。

我们来看一下 Android 4.4 上 AlarmManger 的一部分源代码:

private final boolean mAlwaysExact;
AlarmManager(IAlarmManager service, Context ctx) {
mService = service; final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);
}

看到这里,首选获取应用的 targetSdkVersion,判断是否是小于 Build.VERSION_CODES.KITKAT (即 API Level 19),来设置 mAlwaysExact 变量,表示是否使用精确时间模式。

public static final long WINDOW_EXACT = 0;
public static final long WINDOW_HEURISTIC = -1; private long legacyExactLength() {
return (mAlwaysExact ? WINDOW_EXACT : WINDOW_HEURISTIC);
} public void set(int type, long triggerAtMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null);
}

这里看到,直接影响到 set() 方法给 setImpl() 传入不同的参数,从而影响到了 set() 的执行行为。具体的实现在 AlarmManagerService.java,这里就不往下深究了。

看到这里,发现其实 Android 的 targetSdkVersion 并没有什么特别的,系统使用它也非常直接,甚至很“粗糙”。仅仅是用过下面的 API 来获取 targetSdkVersion,来判断是否执行哪种行为:

getApplicationInfo().targetSdkVersion;

所以,我们可以猜测到,如果 Android 系统升级,发生这种兼容行为的变化时,一般都会在原来的保存新旧两种逻辑,并通过 if-else 方法来判断执行哪种逻辑。果然,在源码中搜索,我们会发现不少类似 getApplicationInfo().targetSdkVersion < Buid.XXXX 这样的代码,相对于浩瀚的 Android 源码量来说,这些还是相对较少了。其实原则上,这种会导致兼容性问题的修改还是越少越好,所以每次发布新的 Android 版本的时候,Android 开发者网站都会列出做了哪些改变,在这里,开发者需要特别注意。

最后,我们也可以理解原文中说的那句话的含义,明白了为什么修改了 APK 的 targetSdkVersion 行为会发生变化,也明白了为什么修改 targetSdkVersion 需要做完整的测试了。

写完这篇文章,再回头去看一下原文的 targetSdkVersion 那一段,发现作者是说的多么“滴水不漏”

Android targetSdkVersion 原理的更多相关文章

  1. Android root 原理

    Android root 原理 0x00 关于root linux和类Unix系统的最初设计都是针对多用户的操作系统,对于用户权限的管理很非常严格的,而root用户(超级用户)就是整个系统的唯一管理员 ...

  2. NFC(6)NFC编程的几个重要类,NFC硬件启动android应用原理

    用于NFC编程的几个重要类 Tag NFC 标签 NfcAdapter Nfc 的适配类 NdefMessage 描述NDEF格式的信息 NdefRecord 描述NDEF信息的一个信息段,类似tab ...

  3. android的原理,为什么不需要手动关闭程序

    转自android的原理,为什么不需要手动关闭程序 不用在意剩余内存的大小,其实很多人都是把使用其他系统的习惯带过来来了. Andoird大多应用没有退出的设计其实是有道理的,这和系统对进程的调度机制 ...

  4. android:targetSdkVersion引起的问题

    项目在三星S3和三星Note II 上调用系统相机点击存储的时候崩溃了.查了半天没弄明白原因,后来发现就是因为在manifest里设置了android:targetSdkVersion = 14,导致 ...

  5. 【转】Android Activity原理以及其子类描述,androidactivity

        Android Activity原理以及其子类描述,androidactivity 简介 Activity是Android应用程序组件,实现一个用户交互窗口,我们可以实现布局填充屏幕,也可以实 ...

  6. 传智播客学习之Android运行原理 (转)

    传智播客学习之Android运行原理 (2010-03-20 22:45:15) 转载▼ 今天终于忙里偷闲,和大家探讨一下android技术,第一次听到3G应该追溯到大学三年级的时候了,记得当时现代通 ...

  7. Android ADB原理及常用命令

    Android调试桥(ADB, Android Debug Bridge)是一个Android命令行工具,包含在SDK 平台工具包中,adb可以用于连接Android设备,或者模拟器,实现对设备的控制 ...

  8. Android分包原理

    如果App引用的库太多,方法数超过65536后无法编译.这是因为单个dex里面不能有超过65536个方法.为什么有最大的限制呢,因为Android会把每一个类的方法id检索起来,存在一个链表结构里面. ...

  9. Android targetSdkVersion 对生命周期的影响

    一直都认为当手机进入休眠时,Activity的生命周期会进入onPause()-->onStop()状态,但是今天偶然遇到了一个百思不得其解的问题,如果在AndroidMainfest.xml文 ...

随机推荐

  1. cocos2dx 安卓真机调试问题汇总

    cocos compile编译apk问题汇总: 1,dx编译报错,没有足够的空间 ANTBUILD : [dx] error : Could not create the Java Virtual M ...

  2. 自动下载google reader里面的星标文章

    1. google reader马上就要关闭了,最后一次看看俺的浏览记录吧 最近 30 天的统计信息 全部订阅: 367 已读条目: 151 已点击的条目:41 个 加星标条目: 16 已发电子邮件条 ...

  3. flexible.js框架改写

    前一阶段拜读了阿里团队的flexible.js,但是flexible的封装感觉还是不完美,因为flexible还是要依赖less/sass之类的编译执行,所以就存了一些问题,我把这些问题进行整理. 优 ...

  4. vim之YCM配置

    BundleInstall,默认会出现错误 ycm_client_support.[so|pyd|dll] and ycm_core.[so|pyd|dll] not detected; you ne ...

  5. 远程连接Linux虚拟机上的mysql失败的解决方法

    今天在虚拟机Ubuntu上折腾了一晚上mysql,然后试着用java连接,搞了很久都没成功,但是同学配好的Debian上却连接成功了,也就是说我的配置有问题. 折腾了很久,最后还是通过理解异常信息来大 ...

  6. 【POJ】1185 炮兵阵地(状压dp)

    题目 传送门:QWQ 分析 看到$ M<=10 $考虑状压. 然后把每行都压一下,那么每个状态相关的就是上一行和上上行的状态. 然后枚举. 然后复杂度最坏是$ O(100 \times 1024 ...

  7. Sqoop导入关系数据库到Hive

    参考:segmentfault.com:Sqoop导入关系数据库到Hive Sqoop 是 apache 下用于 RDBMS 和 HDFS 互相导数据的工具.本文以 mysql 数据库为例,实现关系数 ...

  8. 新手之:SpringBoot ——Reids主从哨兵整合(CentOS7)

    一.Redis主从搭建(一台服务器模拟多个端口) 结构图:) 1.确保安装了Redis,我装在了/opt/redis目录下.可通过"whereis redis-cli"命令查看是否 ...

  9. 二维码名片的格式 - vcard(非常好,可直接添加到手机通讯录)

    分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享   登录|注册     ...

  10. 可视化库-Matplotlib-Pandas与sklearn结合(第四天)

    1. 计算每一种的比例的百分比 import pandas as pd from matplotlib.ticker import FuncFormatter np.random.seed(0) df ...