在一次调试问题中,出现下面错误信息: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文件中,<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为右侧显示。学习
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源码中处处都有相似的判断
。
例子2: Webview类
当设置 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分别须要将程序完整的跑一遍来确保兼容性没有问题。
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) } }//..
在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