Blog / 阅读

android之android.os.NetworkOnMainThreadException异常

by admin on 2014-05-15 16:00:32 in ,



使用android测试访问web服务器的webservice时,在MainActivity的主线程中访问webservice,代码如下:


[java] view plaincopy
package com.example.myandroidpro;  
  
import java.io.File;  
  
import org.ksoap2.SoapEnvelope;  
import org.ksoap2.serialization.SoapObject;  
import org.ksoap2.serialization.SoapSerializationEnvelope;  
import org.ksoap2.transport.HttpTransportSE;  
  
import android.annotation.SuppressLint;  
import android.app.Activity;  
import android.os.Bundle;  
import android.os.Environment;  
import android.os.StrictMode;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.Toast;  
  
public class MainActivity extends Activity {  
  
    private static String NAMESPACE = "http://service.cxf.test/";  
    // webService地址  
    private static String URL = "http://192.168.1.119:8080/CxfWebService/services/HelloService/";  
  
    private String method_name = null;  
    private Button activity_main_btn1;  
  
    @SuppressLint("NewApi") @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();  
        StrictMode.setThreadPolicy(policy);  
          
        File rootDirectory = Environment.getRootDirectory();//获取手机根目录  
        File storageDirectory = Environment.getExternalStorageDirectory();//获取SD卡根目录  
  
        for(File file : rootDirectory.listFiles()){  
            System.err.println(file.isDirectory()+","+file.getName());  
        }   
          
        findVIew();  
          
        activity_main_btn1.setOnClickListener(new OnClickListener() {  
              
            @Override  
            public void onClick(View arg0) {  
                //发送webservice请求  
                    sayHi("zxn");      
            }  
        });  
          
    }  
  
    private void findVIew() {  
        activity_main_btn1 = (Button) findViewById(R.id.activity_main_btn1);  
  
    }  
  
    private String sayHi(String name) {  
        String result = null;  
        // (1) 指定webservice的命名空间和调用的方法名  
        method_name = "sayHi";  
        SoapObject soapObj = new SoapObject(NAMESPACE, method_name);  
        /** 
         * (2) 设置调用方法的参数值,如果没有参数,可以省略。 要注意的是,参数必须和服务声明的@WebParam里面的变量名对应 
         */  
        soapObj.addProperty("name", name);  
        // (3) 生成调用Webservice方法的SOAP请求信息。该信息由SoapSerializationEnvelope对象描述  
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(  
                SoapEnvelope.VER11);  
        // envelope.bodyOut = rpc;  
        envelope.dotNet = false;  
        envelope.setOutputSoapObject(soapObj);  
        // (4)创建HttpTransportsSE对象。通过AndroidHttpTransport类的构造方法可以指定WebService的WSDL文档的URL  
        HttpTransportSE ht = new HttpTransportSE(URL);  
        try {  
            // (5)使用call方法调用WebService方法  
            ht.call(null, envelope);  
            // (6)使用getResponse方法获得WebService方法的返回结果  
            if (envelope.getResponse() != null) {  
                System.out.println(envelope.getResponse());  
                result = String.valueOf(envelope.getResponse());  
                Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT)  
                        .show();  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
  
}  


由于在主线程中访问网络,android版本为4.3,导致如下异常:
[java] view plaincopy
<span style="background-color: rgb(255, 204, 255);">05-15 02:00:05.769: W/System.err(2269): android.os.NetworkOnMainThreadException  
05-15 02:00:05.799: W/System.err(2269):     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1133)</span>  
05-15 02:00:05.799: W/System.err(2269):     at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:84)  
05-15 02:00:05.810: W/System.err(2269):     at libcore.io.IoBridge.connectErrno(IoBridge.java:144)  
05-15 02:00:05.810: W/System.err(2269):     at libcore.io.IoBridge.connect(IoBridge.java:112)  
05-15 02:00:05.869: D/dalvikvm(2269): GC_FOR_ALLOC freed 345K, 14% free 2674K/3076K, paused 48ms, total 52ms  
05-15 02:00:05.869: W/System.err(2269):     at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)  
05-15 02:00:05.880: W/System.err(2269):     at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)  
05-15 02:00:05.880: W/System.err(2269):     at java.net.Socket.connect(Socket.java:842)  
05-15 02:00:05.889: W/System.err(2269):     at libcore.net.http.HttpConnection.<init>(HttpConnection.java:76)  
05-15 02:00:05.889: W/System.err(2269):     at libcore.net.http.HttpConnection.<init>(HttpConnection.java:50)  
05-15 02:00:05.899: W/System.err(2269):     at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:340)  
05-15 02:00:05.899: W/System.err(2269):     at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:87)  
05-15 02:00:05.899: W/System.err(2269):     at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)  
05-15 02:00:05.899: W/System.err(2269):     at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:316)  
05-15 02:00:05.899: W/System.err(2269):     at libcore.net.http.HttpEngine.connect(HttpEngine.java:311)  
05-15 02:00:05.909: W/System.err(2269):     at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)  
05-15 02:00:05.909: W/System.err(2269):     at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)  
05-15 02:00:05.909: W/System.err(2269):     at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81)  
05-15 02:00:05.909: W/System.err(2269):     at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197)  
05-15 02:00:05.919: W/System.err(2269):     at org.ksoap2.transport.ServiceConnectionSE.openOutputStream(ServiceConnectionSE.java:126)  
05-15 02:00:05.919: W/System.err(2269):     at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:185)  
05-15 02:00:05.929: W/System.err(2269):     at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:118)  
05-15 02:00:05.929: W/System.err(2269):     at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:113)  
05-15 02:00:05.969: W/System.err(2269):     at com.example.myandroidpro.MainActivity.sayHi(MainActivity.java:77)  
05-15 02:00:05.969: W/System.err(2269):     at com.example.myandroidpro.MainActivity.access$0(MainActivity.java:58)  
05-15 02:00:05.969: W/System.err(2269):     at com.example.myandroidpro.MainActivity$1.onClick(MainActivity.java:47)  
05-15 02:00:05.969: W/System.err(2269):     at android.view.View.performClick(View.java:4240)  
05-15 02:00:05.979: W/System.err(2269):     at android.view.View$PerformClick.run(View.java:17721)  
05-15 02:00:05.979: W/System.err(2269):     at android.os.Handler.handleCallback(Handler.java:730)  
05-15 02:00:06.012: W/System.err(2269):     at android.os.Handler.dispatchMessage(Handler.java:92)  
05-15 02:00:06.012: W/System.err(2269):     at android.os.Looper.loop(Looper.java:137)  
05-15 02:00:06.019: W/System.err(2269):     at android.app.ActivityThread.main(ActivityThread.java:5103)  
05-15 02:00:06.019: W/System.err(2269):     at java.lang.reflect.Method.invokeNative(Native Method)  
05-15 02:00:06.019: W/System.err(2269):     at java.lang.reflect.Method.invoke(Method.java:525)  
05-15 02:00:06.034: W/System.err(2269):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)  
05-15 02:00:06.034: W/System.err(2269):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)  
05-15 02:00:06.039: W/System.err(2269):     at dalvik.system.NativeStart.main(Native Method)  


原因:
android.os.NetworkOnMainThreadException是说不要在主线程中访问网络,这个是android3.0版本开始就强制程序不能在主线程中访问网络,要把访问网络放在独立的线程中。


解决:
在开发中,为了防止访问网络阻塞主线程,一般都要把访问网络放在独立线程中或者异步线程AsyncTask中。


1、想要忽略这些强制策略问题的话,可以在onCreate()方法里面加上
[java] view plaincopy
StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();  
StrictMode.setThreadPolicy(policy);  
并在方法上加上@SuppressLint("NewApi"),重试,OK。


2、将网络访问放到单独线程中:


[java] view plaincopy
package com.example.myandroidpro;  
  
import java.io.File;  
  
import org.ksoap2.SoapEnvelope;  
import org.ksoap2.serialization.SoapObject;  
import org.ksoap2.serialization.SoapSerializationEnvelope;  
import org.ksoap2.transport.HttpTransportSE;  
  
import android.annotation.SuppressLint;  
import android.app.Activity;  
import android.os.Bundle;  
import android.os.Environment;  
import android.os.Handler;  
import android.os.Looper;  
import android.os.Message;  
import android.os.StrictMode;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.Toast;  
  
public class MainActivity extends Activity {  
  
    private static String NAMESPACE = "http://service.cxf.test/";  
    // webService地址  
    private static String URL = "http://192.168.1.119:8080/CxfWebService/services/HelloService/";  
  
    private String method_name = null;  
    private Button activity_main_btn1;  
  
    private int ANDROID_ACCESS_CXF_WEBSERVICES = 001;   
      
      
    private Handler handler = new Handler(){  
        @Override  
        public void handleMessage(Message msg) {  
            String result = (String) msg.getData().get("result");  
            String obj = (String) msg.obj;//  
            activity_main_btn1.setText("请求结果为:"+result);  
        }  
          
    };  
      
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
          
        File rootDirectory = Environment.getRootDirectory();//获取手机根目录  
        File storageDirectory = Environment.getExternalStorageDirectory();//获取SD卡根目录  
  
        for(File file : rootDirectory.listFiles()){  
            System.err.println(file.isDirectory()+","+file.getName());  
        }   
          
        findVIew();  
          
        activity_main_btn1.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View view) {  
                Thread accessWebServiceThread = new Thread(new WebServiceHandler());  
                accessWebServiceThread.start();  
                  
            }  
        });  
          
    }  
  
    class WebServiceHandler implements Runnable{  
        @Override  
        public void run() {  
            Looper.prepare();  
            String result = sayHi("zxn");  
            Message message = new Message();  
            Bundle bundle = new Bundle();  
            bundle.putString("result", result);  
            message.what = ANDROID_ACCESS_CXF_WEBSERVICES;//设置消息标示  
            message.obj = "zxn";  
            message. setData(bundle);//消息内容  
            handler.sendMessage(message);//发送消息  
            Looper.loop();  
        }  
          
    }  
      
    private void findVIew() {  
        activity_main_btn1 = (Button) findViewById(R.id.activity_main_btn1);  
  
    }  
  
    private String sayHi(String name) {  
        String result = null;  
        // (1) 指定webservice的命名空间和调用的方法名  
        method_name = "sayHi";  
        SoapObject soapObj = new SoapObject(NAMESPACE, method_name);  
        /** 
         * (2) 设置调用方法的参数值,如果没有参数,可以省略。 要注意的是,参数必须和服务声明的@WebParam里面的变量名对应 
         */  
        soapObj.addProperty("name", name);  
        // (3) 生成调用Webservice方法的SOAP请求信息。该信息由SoapSerializationEnvelope对象描述  
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(  
                SoapEnvelope.VER11);  
        // envelope.bodyOut = rpc;  
        envelope.dotNet = false;  
        envelope.setOutputSoapObject(soapObj);  
        // (4)创建HttpTransportsSE对象。通过AndroidHttpTransport类的构造方法可以指定WebService的WSDL文档的URL  
        HttpTransportSE ht = new HttpTransportSE(URL);  
        try {  
            // (5)使用call方法调用WebService方法  
            ht.call(null, envelope);  
            // (6)使用getResponse方法获得WebService方法的返回结果  
            if (envelope.getResponse() != null) {  
                System.out.println(envelope.getResponse());  
                result = String.valueOf(envelope.getResponse());  
                Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT)  
                        .show();  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }  
  
}  
MainActivity的相应布局如下:


[java] view plaincopy
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:paddingBottom="@dimen/activity_vertical_margin"  
    android:paddingLeft="@dimen/activity_horizontal_margin"  
    android:paddingRight="@dimen/activity_horizontal_margin"  
    android:paddingTop="@dimen/activity_vertical_margin"  
    tools:context=".MainActivity" >  
  
    <LinearLayout android:layout_width="fill_parent"  
        android:layout_height="fill_parent"  
        android:orientation="vertical">  
        <TextView  
            android:id="@+id/activity_main_tv1"  
            android:layout_width="match_parent"  
            android:layout_height="wrap_content"  
            android:text="@string/hello_world" />  
  
        <Button  
            android:id="@+id/activity_main_btn1"  
            android:layout_width="match_parent"  
            android:layout_height="wrap_content"  
            android:text="@string/test_for_cxf_webservice" />  
    </LinearLayout>  
</RelativeLayout>  



写评论

相关文章

上一篇:ios项目开发(天气预报项目):通过经纬度获取当前城市名称

下一篇:Android 多分辨率机器适配

评论

写评论

* 必填.

分享

栏目

赞助商


热门文章

Tag 云