Android的最新版本會提供一些很棒的API,您的APP使用新版本API的同時也要兼容舊的Android版本,直到更多設備已更新到新版本的APP。本文檔將向您展示如何利用最新的API,同時繼續支持舊版本。
根據對訪問Google Play商店的設備數量的統計,平台版本分布表會進行定期更新,以顯示運行每個版本的Android設備的分布情況。一般來說,一個APP最好能支持大約90%的活動設備,同時使用最新的Android版本。
提示:為了在多個Android版本中提供最佳特性和功能,您應該在APP中使用Android Support Library,這樣可以在舊版本上使用幾種最新的平台API。
指定Minimum和Target API Levels
AndroidManifest.xml文件描述APP的詳細信息,並標識其支持的Android版本。具體來說,<uses-sdk>元素的minSdkVersion和targetSdkVersion屬性標識了APP兼容的最低和最高API級別。
隨著新版Android的發布,一些風格和行為可能會有所改變。為了讓您的應用程序能夠利用這些更改,並確保您的應用程序適合每個用戶設備的風格,您應該把targetSdkVersion的值設置為最新的Android版本。
在運行時檢查系統版本
Android在Build常量類中為每個平台版本提供了一個唯一的編碼。APP用這個編碼來確保只有系統支持高版本API時,才會執行依賴高版本API的代碼。
注意:解析XML資源時,Android會忽略當前設備不支持的XML屬性。因此,您可以安全地使用僅由較新版本支持的XML屬性,而不必擔心舊版本遇到該代碼時出錯。例如,如果您設置targetSdkVersion =「11」,則APP在Android 3.0及更高版本上默認包含ActionBar。如果要將menu項添加到action bar,您需要在menu資源XML中設置android:showAsAction =「ifRoom」。 在跨版本的XML文件中可以安全地執行此操作,因為較舊版本的Android只會忽略showAsAction屬性(即,不需要在res / menu-v11 /中添加一個單獨的menu資源)。
2. 如何控制android系統中NavigationBar 的顯示與隱藏
我們使用的大多數android手機上的Home鍵,返回鍵以及menu鍵都是實體觸摸感應按鍵。如果你用Google的Nexus4或Nexus5話,你會發現它們並沒有實體按鍵或觸摸感應按鍵,取而代之的是在屏幕的下方加了一個小黑條,在這個黑條上有3個按鈕控制項,這種設置無疑使得手機的外觀的設計更加簡約。但我遇到身邊用Nexus 4手機的人都吐槽這種設計,原因很簡單:好端端的屏幕,被劃出一塊區域用來顯示3個按鈕(如下圖所示):Back, Home, Recent。並且它一直用在那裡佔用著。
在android源碼中,那一塊區域被叫做NavigationBar。同時,google在代碼中也預留了標志,用來控制它的顯示與隱藏。NavigationBar的顯示與隱藏的控制是放在SystemU中的,具體的路徑是:\frameworks\base\packages\SystemUI。對android4.0以上的手機而言,SystemUi包含兩部分:StatusBar和NavigationBar。在SystemUI的工程下有一個類PhoneStatusBar.java,在該類中可以發現關於控制NavigationBar的相關代碼:
在start()方法里可以看到NavigationBar是在那時候被添加進來,但只是添加,決定它顯示還是隱藏是在後面控制的。
<span style="font-size:18px;">@Override
public void start() {
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
updateDisplaySize();
/// M: Support Smartbook Feature.
if (SIMHelper.isMediatekSmartBookSupport()) {
/// M: [ALPS01097705] Query the plug-in state as soon as possible.
mIsDisplayDevice = SIMHelper.isSmartBookPluggedIn(mContext);
Log.v(TAG, "start, mIsDisplayDevice=" + mIsDisplayDevice);
}
super.start(); // calls createAndAddWindows()
addNavigationBar();
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext);
mHeadsUpObserver.onChange(true); // set up
if (ENABLE_HEADS_UP) {
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SETTING_HEADS_UP), true,
mHeadsUpObserver);
}
}</span>
其中的addNavigationBar()具體的實現方法如下:
<span style="font-size:18px;"> // For small-screen devices (read: phones) that lack hardware navigation buttons
private void addNavigationBar() {
if (DEBUG) Slog.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
if (mNavigationBarView == null) return;
prepareNavigationBarView();
mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
}</span>
可以看到Navigationbar實際上windowmanager向window窗口裡添加一個view。在調用addNavigationBar()方法之前會回調start()的父方法super.start()來判斷是否要添加NavigationBar。在super.start()的調用父類方法里會調用createAndAddWindows(),該方法內會判斷是否需要添加顯示NavigationBar,然後決定是否要實例化NavigationBarView.
<span style="font-size:18px;">try {
boolean showNav = mWindowManagerService.hasNavigationBar();
if (DEBUG) Slog.v(TAG, "hasNavigationBar=" + showNav);
if (showNav) {
mNavigationBarView =
(NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
mNavigationBarView.setDisabledFlags(mDisabled);
mNavigationBarView.setBar(this);
}
} catch (RemoteException ex) {
// no window manager? good luck with that
}</span>
WindowManagerService類實現了WindowManagerPolicy的介面,所以WindowManagerService會回調WindowManagerPolicy 的hasNavigationBar()介面,
<span style="font-size:18px;"> @Override
public boolean hasNavigationBar() {
return mPolicy.hasNavigationBar();
}</span>
Policy向下調用實際上調用的是PhoneWindowManager實現的hasNavigationBar方法,下面代碼是PhoneWindowManager中的hasNavigationBar()方法。
<span style="font-size:18px;">// Use this instead of checking config_showNavigationBar so that it can be consistently
// overridden by qemu.hw.mainkeys in the emulator.
public boolean hasNavigationBar() {
return mHasNavigationBar;
}</span>
而mHasNavigationBar的賦值可以在PhoneWindowManager中的setInitialDisplaySize(Display display, int width, int height, int density)方法中找到,
<span style="font-size:18px;"> if (!mHasSystemNavBar) {
mHasNavigationBar = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_showNavigationBar);
// Allow a system property to override this. Used by the emulator.
// See also hasNavigationBar().
String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
if (! "".equals(navBarOverride)) {
if (navBarOverride.equals("1")) mHasNavigationBar = false;
else if (navBarOverride.equals("0")) mHasNavigationBar = true;
}
} else {
mHasNavigationBar = false;
}</span>
從上面代碼可以看到mHasNavigationBar的值的設定是由兩處決定的:
1.首先從系統的資源文件中取設定值config_showNavigationBar, 這個值的設定的文件路徑是frameworks/base/core/res/res/values/config.xml
<!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
autodetected from the Configuration. -->
<bool name="config_showNavigationBar">false</bool>
2.然後系統要獲取「qemu.hw.mainkeys」的值,這個值可能會覆蓋上面獲取到的mHasNavigationBar的值。如果 「qemu.hw.mainkeys」獲取的值不為空的話,不管值是true還是false,都要依據後面的情況來設定。
所以上面的兩處設定共同決定了NavigationBar的顯示與隱藏。