Windows環境下Android Studio系列8—SDK版本配置

1. 問題的由來

在一次調試問題中,出現下面錯誤信息:html

09-07 09:15:08.000    1342-1342/? W/System.err﹕ android.os.NetworkOnMainThreadException
09-07 09:15:08.000    1342-1342/? W/System.err﹕ at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1133)
09-07 09:15:08.000    1342-1342/? W/System.err﹕ at java.net.InetAddress.lookupHostByName(InetAddress.java:385)
09-07 09:15:08.000    1342-1342/? W/System.err﹕ at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
09-07 09:15:08.000    1342-1342/? W/System.err﹕ at java.net.InetAddress.getByName(InetAddress.java:289)
略。。。。。。

後來百度/Google"android.os.NetworkOnMainThreadException", [1]中在2013-06-24的博文中就指出:NetworkOnMainThreadException是由於應用程序在主線程上嘗試網絡操做。另外,這個異常在Honeycomb SDK或更高版本的SDK上纔會拋出。低版本的SDK容許應用程序在主線程或loop線程執行網絡操做,但不鼓勵這樣作。應該放到子線程中,而後當子線程完成以後再發廣播也好,message也好,通知主線程作相應的UI更改,或利用AsyncTask來作網絡操做。java

這個問題涉及到AndroidManifest.xml文件中的SDK版本配置,並且隨着Android Studio缺省使用Gradle來編譯,build.gradle文件中也存在相應的SDK版本配置,那麼如何來正確地配置這些SDK版本呢?android

2. AndroidManifest.xml文件中的minSdkVersion與targetSdkVersion

參考[2], AndroidManifest.xml文件中,<uses-sdk>標籤中有minSdkVersion, targetSdkVersion, maxSdkVersion三個屬性,因爲maxSdkVersion屬性已經再也不推薦配置,所以下面主要討論另外兩個屬性。shell

首先minSdkVersion與targetSdkVersion都是整數值,一般都須要配置而不要採用默認值。android-studio

minSdkVersion是應用程序運行所需的SDK最低版本。若是不指明該屬性,其默認值爲1。若是Android手機版本低於這個值,應用程序將安裝失敗。網絡


[3]中經過查看Android源碼和兩個例子來理解targetSdkVersion
app

例子1: DatePickerDialog組件oop

當AndroidManifest.xml文件中 targetSDKversion屬性設置不一樣的值,DatePickerDialog組件表現會不一樣。若是設置的值爲10或更低的值,DatePickerDialog爲左側顯示。若是設置的值爲11或更高的值,DatePickerDialog爲右側顯示。學習

DatePickerDialog look with targetSDKversion 10 or lower DatePickerDialog look with targetSDKversion 11 or higher

Android源碼以下(注意:下面代碼可能在最新的SDK版本中有變化,但判斷targetSdkVersion的邏輯沒變):測試

public DatePickerDialog(Context context,
    OnDateSetListener callBack,
    int year,
    int monthOfYear,
    int dayOfMonth,
    boolean yearOptional) {
        this(context, context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB                
                ? com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert
                : com.android.internal.R.style.Theme_Dialog_Alert,
        callBack, year, monthOfYear, dayOfMonth, yearOptional);
}

在第7行根據設置的targetSDKversion來設置不一樣的theme:getApplicationInfo().targetSdkVersion >= SOME_VERSION。實際上在Android源碼中處處都有相似的判斷

例子2Webview類

當設置 targetSDKversion屬性爲18或更高值時,Webview類的public方法應當在主線程中調用,不然運行時系統將拋出一個RuntimeException。可參見下面源代碼:

sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >=
            Build.VERSION_CODES.JELLY_BEAN_MR2;
    
if (sEnforceThreadChecking) {
    throw new RuntimeException(throwable);
}

Android官方文檔中提到, 隨着Android新版本的發展,一些行爲甚至appearances 可能發生改變從前面兩個例子已經能夠看出。

總結一下:當設置targetSdkVersion爲更高的值時,就像DatePickerDialog例子中那樣會有appearance加強的好處,但正如Webview例子那樣,之前在低版本中正常運行的代碼,若是修改targetSdkVersion爲更高時可能會引起致命錯誤,但此時在開發階段就能夠修訂代碼來適應更高的targetSdkVersion所以targetSdkVersion屬性告訴系統該應用已經在target Version系統上進行了充分測試。

但可能targetSdkVersion這個SDK版本中的某個新特性在低版本中是不支持的,那麼在低版本的API設備上運行程序時,可能會報錯:java.lang.VerifyError。也就是說,此屬性不會幫你解決兼容性的測試問題。你至少須要在minSdkVersion這個版本上將程序完整的跑一遍來肯定兼容性是沒有問題的。

所以,須要在minSdkVersion與targetSdkVersion分別須要將程序完整的跑一遍來確保兼容性沒有問題。

3. build.gradle中的SDK版本配置 

build.gradle中會有如下代碼:

android {
        compileSdkVersion 19
        buildToolsVersion "21.1.1"
     
        defaultConfig {
            minSdkVersion 8
            targetSdkVersion 19
        }

AndroidManifest.xml文件中有如下代碼:

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="8"/>

Gradle文件會覆蓋manifest文件中的值,能夠不用管mainfest文件中的值,將minSdkVersion和targetSdkVersion都在Gradle文件中配置便可,也能夠刪除mainfest文件中的<uses-sdk>標籤。


在build.gradle文件中,

compileSdkVersion是編譯時Android的API level。

buildToolsVersion是編譯器(aapt, dx, renderscript compiler等)的版本. 從版本18開始的每一個API level, 會有一個匹配的.0.0編譯器版本。例如在IO 2014, 發佈了API 20和build-tools 20.0.0。

minSdkVersion與targetSdkVersion在前面已經討論過。

注意:targetSdkVersion不該當超過compileSdkVersion。


在[4]中還給出了一種統一各個版本的方法:

編輯 gradle.properties 文件,增長如下代碼:

ANDROID_BUILD_MIN_SDK_VERSION=14
ANDROID_BUILD_TARGET_SDK_VERSION=21
ANDROID_BUILD_TOOLS_VERSION=21.1.3
ANDROID_BUILD_SDK_VERSION=21

而後,就能夠在 build.gradle 文件中這樣使用:

//...android {
    compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)
    buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION

    defaultConfig {
        minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION)
        targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
    }
}//..

4. 遺留問題 

在build.gradle文件中,除了上述與版本相關的配置之外,在dependencies中也涉及編譯期間的版本配置,這留待後續再學習研究:

dependencies {
    compile 'com.android.support:support-v4:20.0.0'
    
    // your unit test dependencies as described in the article
    unitTestCompile files("$project.buildDir/classes/release")
    unitTestCompile 'junit:junit:4.11'
    unitTestCompile 'com.google.android:android:4.1.1.4'
    unitTestCompile 'org.robolectric:robolectric:2.1.1'

    // duplicate these dependencies in the instrumentTestCompile scope 
    // in order to have the integration in Android Studio (autocompletion and stuff)
    instrumentTestCompile 'junit:junit:4.11'
    instrumentTestCompile 'org.robolectric:robolectric:2.1.1'
}


5. 參考資料

[1] android.os.NetworkOnMainThreadException的解決方案, 2013-06-24, http://www.cnblogs.com/kissazi2/archive/2013/06/24/3153307.html

[2] Android中<uses-sdk>屬性和target屬性分析, 2014-06-03, http://blog.csdn.net/fuzhengchao/article/details/28121193

[3] Android Min SDK Version vs. Target SDK Version, http://stackoverflow.com/questions/4568267/android-min-sdk-version-vs-target-sdk-version

[4] How do I add a library project to the Android Studio?http://stackoverflow.com/questions/16588064/how-do-i-add-a-library-project-to-the-android-studio/16639227#16639227

相關文章
相關標籤/搜索