Android targetSdkVersion详解
Android targetSdkVersion 原理
17 January 2016前幾天 Google 官方發(fā)布文章解析 compileSdkVersion、minSdkVersion 以及 targetSdkVersion 的含義,以及合理設(shè)置各個值的意義,原文 Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion(后面簡稱 “原文”),還有翻譯版。
其中,compileSdkVersion 和 minSdkVersion 都非常好理解,前者表示編譯的 SDK 版本,后者表示應(yīng)用兼容的最低 SDK 版本。但是對于 targetSdkVersion 其實很難一句話解析清楚,原文用了“萬能”的詞 —— interesting 來描述。以前我也有一些迷糊,看到有些人和我有同樣的困惑,本文試圖徹底解決這個問題。
原文是這么說的:
targetSdkVersion is the main way Android provides forward compatibility
targetSdkVersion 是 Android 系統(tǒng)提供前向兼容的主要手段。這是什么意思呢?隨著 Android 系統(tǒng)的升級,某個系統(tǒng)的 API 或者模塊的行為可能會發(fā)生改變,但是為了保證老 APK 的行為還是和以前兼容。只要 APK 的 targetSdkVersion 不變,即使這個 APK 安裝在新 Android 系統(tǒng)上,其行為還是保持老的系統(tǒng)上的行為,這樣就保證了系統(tǒng)對老應(yīng)用的前向兼容性。
這里還是用原文的例子,在 Android 4.4 (API 19)以后,AlarmManager 的 set() 和 setRepeat() 這兩個 API 的行為發(fā)生了變化。在 Android 4.4 以前,這兩個 API 設(shè)置的都是精確的時間,系統(tǒng)能保證在 API 設(shè)置的時間點上喚醒 Alarm。因為省電原因 Android 4.4 系統(tǒng)實現(xiàn)了 AlarmManager 的對齊喚醒,這兩個 API 設(shè)置喚醒的時間,系統(tǒng)都對待成不精確的時間,系統(tǒng)只能保證在你設(shè)置的時間點之后某個時間喚醒。
這時,雖然 API 沒有任何變化,但是實際上 API 的行為卻發(fā)生了變化,如果老的 APK 中使用了此 API,并且在應(yīng)用中的行為非常依賴 AlarmManager 在精確的時間喚醒,例如鬧鐘應(yīng)用。如果 Android 系統(tǒng)不能保證兼容,老的 APK 安裝在新的系統(tǒng)上,就會出現(xiàn)問題。
Android 系統(tǒng)是怎么保證這種兼容性的呢?這時候 targetSdkVersion 就起作用了。APK 在調(diào)用系統(tǒng) AlarmManager 的 set() 或者 setRepeat() 的時候,系統(tǒng)首先會查一下調(diào)用的 APK 的 targetSdkVersion 信息,如果小于 19,就還是按照老的行為,即精確設(shè)置喚醒時間,否者執(zhí)行新的行為。
我們來看一下 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); }看到這里,首選獲取應(yīng)用的 targetSdkVersion,判斷是否是小于 Build.VERSION_CODES.KITKAT (即 API Level 19),來設(shè)置 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() 傳入不同的參數(shù),從而影響到了 set() 的執(zhí)行行為。具體的實現(xiàn)在 AlarmManagerService.java,這里就不往下深究了。
看到這里,發(fā)現(xiàn)其實 Android 的 targetSdkVersion 并沒有什么特別的,系統(tǒng)使用它也非常直接,甚至很“粗糙”。僅僅是用過下面的 API 來獲取 targetSdkVersion,來判斷是否執(zhí)行哪種行為:
getApplicationInfo().targetSdkVersion;所以,我們可以猜測到,如果 Android 系統(tǒng)升級,發(fā)生這種兼容行為的變化時,一般都會在原來的保存新舊兩種邏輯,并通過 if-else 方法來判斷執(zhí)行哪種邏輯。果然,在源碼中搜索,我們會發(fā)現(xiàn)不少類似 getApplicationInfo().targetSdkVersion < Buid.XXXX 這樣的代碼,相對于浩瀚的 Android 源碼量來說,這些還是相對較少了。其實原則上,這種會導(dǎo)致兼容性問題的修改還是越少越好,所以每次發(fā)布新的 Android 版本的時候,Android 開發(fā)者網(wǎng)站都會列出做了哪些改變,在這里,開發(fā)者需要特別注意。
最后,我們也可以理解原文中說的那句話的含義,明白了為什么修改了 APK 的 targetSdkVersion 行為會發(fā)生變化,也明白了為什么修改 targetSdkVersion 需要做完整的測試了。
寫完這篇文章,再回頭去看一下原文的 targetSdkVersion 那一段,發(fā)現(xiàn)作者是說的多么“滴水不漏”。
總結(jié)
以上是生活随笔為你收集整理的Android targetSdkVersion详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP、UDP和HTTP详解
- 下一篇: 关于Android消息机制你所需要知道的