关于Android程序使用KSoap2调用Webservice运行不成功的问题
公司的一个旧项目,用到了KSoap2访问Webservice,再编译运行时报android.os.NetworkOnMainThreadException
异常。
原代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import java.io.IOException; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;
import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.PropertyInfo; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import org.xmlpull.v1.XmlPullParserException;
import android.os.AsyncTask; import android.os.Handler; import android.util.Log;
public class Service_conn { String TAG = this.getClass().getSimpleName(); private static final String NAMESPACE = "WebService"; SoapObject soap_request; HttpTransportSE ht; SoapSerializationEnvelope envelope; private SoapObject soap_result = null;
public SoapObject SEND_MESSAGE(final String method_name, List<NameValue> param) throws Exception { soap_request = new SoapObject(NAMESPACE, method_name); if (param != null) { for (int i = 0; i < param.size(); i++) { Log.e(TAG, "参数:" + param.get(i).getName() + "=" + param.get(i).getValue()); soap_request.addProperty(param.get(i).getName(), param.get(i).getValue()); } } envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true; envelope.setOutputSoapObject(soap_request); ht = new HttpTransportSE(SocketService.URL); ht.debug = true; Log.e(TAG, "URL:" + SocketService.URL + " NAMESPACE:" + NAMESPACE + " method_name:" + method_name);
ht.call(NAMESPACE+"/"+method_name, envelope); soap_result = (SoapObject) envelope.bodyIn; return soap_result; } }
|
从Honeycomb SDK(3.0)开始,google不再允许网络请求(HTTP、Socket)等相关操作直接在Main Thread类中。既然不允许放在主线程那就另开线程执行,但这样结果要跑回主线程就要通过 interface 回调跑回主线程,进而所有调用该方法的方法都要加一 interface 参数,这样改动太大了。
在Java中一般通过继承Thread类或者实现Runnable接口这两种方式来创建多线程,但是这两种方式都有个缺陷,就是不能在执行完成后获取执行的结果,因此Java 1.5之后提供了Callable和Future接口,通过它们就可以在任务执行完毕之后得到任务的执行结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| FutureTask<SoapObject> futureTask = new FutureTask<SoapObject>( new Callable<SoapObject>() { @Override public SoapObject call() throws Exception { try { ht.call(NAMESPACE + "/" + method_name, envelope); if (envelope.getResponse() != null) { SoapObject object = (SoapObject) envelope.bodyIn; String result = object.getProperty(0) .toString(); LogUtil.E("Service_conn", result); return object; } } catch (Exception e) { e.printStackTrace(); } return null; } }); new Thread(futureTask).start(); try { soap_result = futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }
|
这样不需要在回调中获取结果。
最终代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| import java.io.IOException; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;
import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.PropertyInfo; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; import org.xmlpull.v1.XmlPullParserException;
import android.os.AsyncTask; import android.os.Handler; import android.util.Log;
public class Service_conn { String TAG = this.getClass().getSimpleName(); private static final String NAMESPACE = "WebService"; SoapObject soap_request; HttpTransportSE ht; SoapSerializationEnvelope envelope; private SoapObject soap_result = null;
public SoapObject SEND_MESSAGE(final String method_name, List<NameValue> param) throws Exception { soap_request = new SoapObject(NAMESPACE, method_name); if (param != null) { for (int i = 0; i < param.size(); i++) { Log.e(TAG, "参数:" + param.get(i).getName() + "=" + param.get(i).getValue()); soap_request.addProperty(param.get(i).getName(), param.get(i).getValue()); } } envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true; envelope.setOutputSoapObject(soap_request); ht = new HttpTransportSE(SocketService.URL); ht.debug = true; Log.e(TAG, "URL:" + SocketService.URL + " NAMESPACE:" + NAMESPACE + " method_name:" + method_name);
FutureTask<SoapObject> futureTask = new FutureTask<SoapObject>( new Callable<SoapObject>() { @Override public SoapObject call() throws Exception { try { ht.call(NAMESPACE + "/" + method_name, envelope); if (envelope.getResponse() != null) { SoapObject object = (SoapObject) envelope.bodyIn; String result = object.getProperty(0) .toString(); LogUtil.E("Service_conn", result); return object; } } catch (Exception e) { e.printStackTrace(); } return null; } }); new Thread(futureTask).start(); try { soap_result = futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return soap_result; } }
|