android之android.os.NetworkOnMainThreadException异常

来源:互联网 发布:mac原版镜像 编辑:程序博客网 时间:2024/06/05 16:08

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

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,导致如下异常:

<span style="background-color: rgb(255, 204, 255);">05-15 02:00:05.769: W/System.err(2269): android.os.NetworkOnMainThreadException05-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 52ms05-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中。

 先在AndroidManifest.xml文件manifest节点中添加如下配置:

<uses-permission android:name="android.permission.INTERNET"/>

1、想要忽略这些强制策略问题的话,可以在onCreate()方法里面加上

StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();StrictMode.setThreadPolicy(policy);
并在方法上加上@SuppressLint("NewApi"),重试,OK。


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

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(){@Overridepublic 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() {@Overridepublic void onClick(View view) {Thread accessWebServiceThread = new Thread(new WebServiceHandler());accessWebServiceThread.start();}});            }    class WebServiceHandler implements Runnable{@Overridepublic 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文档的URLHttpTransportSE 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的相应布局如下:

<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>

3、将网络访问放到异步任务AsyncTask中,代码如下:

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.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.os.Environment;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;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;    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() {@Overridepublic void onClick(View view) {accessWSAction();}private void accessWSAction() {new AsyncTask<String, Void, Object>() {//在doInBackground 执行完成后,onPostExecute 方法将被UI 线程调用,// 后台的计算结果将通过该方法传递到UI 线程,并且在界面上展示给用户.protected void onPostExecute(Object result) {super.onPostExecute(result);activity_main_btn1.setText("请求结果为:"+result);//可以更新UI}//该方法运行在后台线程中,因此不能在该线程中更新UI,UI线程为主线程protected Object doInBackground(String... params) {String result = sayHi("zxn");//activity_main_btn1.setText("请求结果为:"+result);return result;}}.execute();}});    }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文档的URLHttpTransportSE 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;}}



0 0
原创粉丝点击