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

1. 问题的由来

在一次调试问题中,出现下面错误信息:

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来做网络操作。

这个问题涉及到AndroidManifest.xml文件中的SDK版本配置,而且随着Android Studio缺省使用Gradle来编译,build.gradle文件中也存在相应的SDK版本配置,那么如何来正确地配置这些SDK版本呢?

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

参考[2], AndroidManifest.xml文件中,<uses-sdk>标签中有minSdkVersion, targetSdkVersion, maxSdkVersion三个属性,由于maxSdkVersion属性已经不再推荐配置,因此下面主要讨论另外两个属性。

首先minSdkVersion与targetSdkVersion都是整数值,通常都需要配置而不要采用默认值。

minSdkVersion是应用程序运行所需的SDK最低版本。如果不指明该属性,其默认值为1。如果Android手机版本低于这个值,应用程序将安装失败。


[3]中通过查看Android源码和两个例子来理解targetSdkVersion

例子1: DatePickerDialog组件

当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

你可能感兴趣的:(Windows环境下Android Studio系列8—SDK版本配置)