自己关于Android 通过WebService进行网络编程的总结


          平时在开发中,都是使用http协议发送get或post方法,得到一个json的字符串,然后解析封装。

          

         但是今天遇到一个项目,是使用android去调用WebService接口来获取数据,得到的是一个xml的字符串并对其进行封装。这里就遇到2个问题。


1、android上如何去调用一个webService? 网络上关于这里的资料也比较多,但是要自己真正开发才能了解整个流程。这里我参考了以下几篇文章


(1)、http://www.cnblogs.com/shenliang123/archive/2012/07/05/2578586.html

这篇文章从整体流程,介绍了如何android上如何调用webService,之前不了解什么是webService或者是android开发者刚接触调用webService的同学,都可以看看。


(2)、http://blog.csdn.net/xiaanming/article/details/16871117

这篇文章最大的亮点是使用了一个自定义的封装工具类,对调用webService进行了很好的封装,以后调用就变得相对简单了。但是博文提供的一个Demo,最后查看某个城市具体天气无法查询。所以最好还是自己写一次,加深理解。


(3)、http://blog.csdn.net/menhin/article/details/11955207

            http://bbs.csdn.net/topics/350047287


             http://blog.csdn.net/lyq8479/article/details/6428288(11月27日更新另外一个参考文章)

以上文章是开发中遇到的一些问题,有需要的同学可以参考下



2、xml的数据解析封装其实相比json,是复杂不少的,一般常用的是用到pull解析。而且要更具xml内容不同写不同的解析方法,其实很繁琐。


接下来整个过程遇到了不少问题,也有不少总结,结合上面的博文和自己理解在这里写下来我的一些理解。



              首先,android上究竟如何调用webService呢,整个流程如下:



1、先使用一个叫ksoap2的jar包,最新的是3.0版,把它放入lib包下即可,点击我下载,注意检查eclipse中的android private libraries中是否有编译通过,如有下图就表示成功。


2、创建HttpTransportsSE对象。通过HttpTransportsSE类的构造方法可以指定WebService的WSDL文档的URL,也就是webService的访问地址。

 HttpTransportSE httpTransportSE = new HttpTransportSE(url);


3、创建SoapObject对象,里面的参数分别是WebService的命名空间和调用方法名。

         SoapObject soapObject = new SoapObject(NAMESPACE, methodName);


4、设置调用方法的参数值,如果没有参数,就不设置,有参数的话调用SoapObject对象的addProperty(String name, Object value)方法将参数加入到SoapObject对象中。(注意:设置参数时,参数名不一定需要跟调用的服务器端的参数名相同,只需要对应的顺序相同即可)

       soapObject.addProperty(“参数名字”, “传递的参数值”);


5、实例化SoapSerializationEnvelope,传入WebService的SOAP协议的版本号。(可以比服务器的版本更低,但是不能更高。比如最后的VER11为VER12就会出错。这里要跟服务端开发的沟通,确定soap的版本号是多少)

       SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);


6、通过setOutputSoapObject(Object soapObject)将上面第3步创建的SoapObject对象设置到里面,并设置是否调用的是.Net开发的WebService和是否debug等信息。
soapEnvelope.setOutputSoapObject(soapObject);

soapEnvelope.dotNet = true;
httpTransportSE.debug = true;


7、我们在线程中调用HttpTransportsSE对象的call方法就能实现对WebService的调用,其中,第一个参数为命名空间+调用方法,第二个参数为第5步建立的SoapSerializationEnvelope对象因为涉及到网络操作,所以使用了线程池来异步操作调用WebService接。

                     httpTransportSE.call(NAMESPACE + methodName, soapEnvelope);


8、通过soapEnvelope.bodyIn获取WebService返回的信息。返回对象是SoapObject类型,该对象就代表Webservice的返回消息,析该对象,即可获得调用web service的返回值。

             SoapObject   resultSoapObject = (SoapObject) soapEnvelope.bodyIn;



讲了这么多,说说具体怎么使用,下面的例子用了第2篇博客的一个工具类

现在我有一个webService,访问地址是

http://192.168.1.101:8080/webservice/LoginWebservice?wsd

 

里面有一个方法getLoginXml,参数的类型是String字符串,参数的名字inputXmlString

该方法的功能是,你随便传递一个字符串,服务端会打印你字符串,并返回下面xml格式的字符串

package com.example.webservice;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.http.client.HttpResponseException;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;
import android.os.Handler;
import android.os.Message;

/**
 * 访问WebService的工具类,使用了线程池
 * 
 * @see http://blog.csdn.net/xiaanming
 * 
 * @author xiaanming
 * 
 */
public class WebServiceUtils {

	//下面这个是本机的服务器地址,使用前需要先部署
	//注意,这里的url地址,如果有?wsdl,必须去掉!!!!比如下面的第2个地址就不行,会出现异常org.xmlpull.v1.XmlPullParserException: expected: START_TAG
	public static final String WEB_SERVER_URL = "http://192.168.1.101:8080/webservice/LoginWebservice";
	//public static final String WEB_SERVER_URL = "http://192.168.1.101:8080/webservice/LoginWebservice?wsdl";
	
	
	// 含有3个线程的线程池                   
	private static final ExecutorService executorService = Executors
			.newFixedThreadPool(3); 
	
	// 命名空间 ,注意有的最后带一个反斜杠,有的没有,这里要查看wsdl文档,具体设置。可以比较如下
	//private static final String NAMESPACE = "http://WebXml.com.cn/";、
	private static final String NAMESPACE = "http://webservice";

	/**
	 * 
	 * @param url
	 *            WebService服务器地址
	 * @param methodName
	 *            WebService的调用方法名
	 * @param properties
	 *            WebService的参数
	 * @param webServiceCallBack
	 *            回调接口,这个回调接口是自己写的
	 */
	public static void callWebService(String url, final String methodName,
			HashMap<String, String> properties,
			final WebServiceCallBack webServiceCallBack) {
		
		//第1步:先使用一个叫ksoap2的jar包,最新的是3.0版,把它放入lib包下即可
		
		// 第2步   : 创建HttpTransportSE对象,传递WebService服务器地址
		final HttpTransportSE httpTransportSE = new HttpTransportSE(url);
		
		// 第3步:创建SoapObject对象 
		SoapObject soapObject = new SoapObject(NAMESPACE, methodName);
        
		//第4步:如果有参数传给Web Service服务器端,调用SoapObject对象的addProperty(String name, Object value)方法来设置参数,该方法的name参数指定参数名
		// SoapObject添加参数
		if (properties != null) {
			for (Iterator<Map.Entry<String, String>> it = properties.entrySet()
					.iterator(); it.hasNext();) {
				Map.Entry<String, String> entry = it.next();
			
				//下面这一句就是给服务端传递数据,    分别是参数的名字和 参数的值
				//注意:设置参数,参数名不一定需要跟调用的服务器端的参数名相同,只需要对应的顺序相同即可!!!!!!!!
				soapObject.addProperty(entry.getKey(), entry.getValue());
			}
		}

		// 第5步 :实例化SoapSerializationEnvelope,传入WebService的SOAP协议的版本号
		//可以比服务器的版本更低,但是不能更高。比如最后的VER11为VER12就会出错。这里要跟服务端开发的沟通,确定soap的版本号是多少
		final SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(
				SoapEnvelope.VER11);
		
		//第6步:将上面的第3步建立的SoapObject对象通过setOutputSoapObject(Object soapObject)设置到里面,并设置是否调用的是.Net开发的WebService和是否debug等信息
		soapEnvelope.setOutputSoapObject(soapObject);
		
		// 设置是否调用的是.Net开发的WebService
		soapEnvelope.dotNet = true;
		httpTransportSE.debug = true;

		// 用于子线程与主线程通信的Handler
		final Handler mHandler = new Handler() {

			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				// 将返回值回调到callBack的参数中  
				
				//SoapObject就是服务端返回的参数,需要解析它即可
				webServiceCallBack.callBack((SoapObject) msg.obj);
			}

		};

		// 开启线程去访问WebService
		executorService.submit(new Runnable() {

			@Override
			public void run() {
				SoapObject resultSoapObject = null;
				try {
					//第7步:我们在线程中调用HttpTransportsSE对象的call方法就能实现对WebService的调用,其中,第一个参数为命名空间+调用方法,第二个参数为第5步建立的SoapSerializationEnvelope对象(因为涉及到网络操作,所以使用了线程池来异步操作调用WebService接。)
					httpTransportSE.call(NAMESPACE + methodName, soapEnvelope);
					if (soapEnvelope.getResponse() != null) {
						
					// 第8步:通过soapEnvelope.bodyIn,获取服务器响应返回的SoapObject,该对象就代表Webservice的返回消息,
						//解析该对象,即可获得调用web service的返回值
						
						resultSoapObject = (SoapObject) soapEnvelope.bodyIn;
					}
				} catch (HttpResponseException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (XmlPullParserException e) {
					e.printStackTrace();
				} finally {
					// 将获取的消息利用Handler发送到主线程
					mHandler.sendMessage(mHandler.obtainMessage(0,
							resultSoapObject));
				}
			}
		});
	}

	/**
	 * 
	 * 
	 * @author xiaanming
	 * 
	 */
	public interface WebServiceCallBack {
		public void callBack(SoapObject result);
	}

}


工具类写好了,那怎么使用呢

package com.example.webservice;
import java.util.HashMap;
import org.ksoap2.serialization.SoapObject;
import com.example.mydemo.R;
import com.example.webservice.WebServiceUtils.WebServiceCallBack;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

/**
 *  通过这个来实现
 * @author hemiy
 * @copyright 
 */
public class TestWebservice extends Activity {
	
	    private TextView text;
	    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        	super.onCreate(savedInstanceState);
        	setContentView(R.layout.activity_test_webservice);
        	text=(TextView) findViewById(R.id.content);
        	
        }
       
        public void testWeb(View view){
        	//显示进度条  
            ProgressDialogUtils.showProgressDialog(this, "数据加载中...");  
              
            //添加参数  
            HashMap<String, String> properties = new HashMap<String, String>();  
        
            //其实这里的key可以为任意字符串,但是不能为数字的字符串
            // 比如  properties.put("1", "这里是自己封装好上传的xml格式数据"); 
           // 会报异常 java.io.IOException: HTTP request failed, HTTP status: 500
            properties.put("h", "这里是自己封装好上传的xml格式字符串数据");  
              
            WebServiceUtils.callWebService(WebServiceUtils.WEB_SERVER_URL, "getLoginXml", properties, new WebServiceCallBack() {  
                  
              //调用返回的数据执行如下的代码
                public void callBack(SoapObject result) {  
                	
                    ProgressDialogUtils.dismissProgressDialog();  
                    
                    if(result != null){  
                    	String name = result.getProperty(0).toString();
                    	text.setText(name);
                    }else{  
                        Toast.makeText(TestWebservice.this, "获取数据错误", Toast.LENGTH_SHORT).show();  
                    }  
                }  
            });  
        }
}


tomcat服务器的打印结果,表示成功。





开发中遇到问题

1、android连接webservice报java.io.Exception: Http request failed,Http status 500 tran.call出错。

http 500错误是服务器内部错误,确认你是否安装接口指定参数格式提交或者与服务器端沟通确认。


2、注意命名空间是否带下划线;


3、注意传递的参数“名字”是否正确,有的服务端要求名字一定要指定的,如天气预报。而自己的服务器除了数字字符串,其实可以任意取名


项目源码


4、这里的服务器url地址,如果有?wsdl,必须去掉!!!!

比如下面的地址就不行,会出现异常org.xmlpull.v1.XmlPullParserException: expected: START_TAG
public static final String WEB_SERVER_URL = "http://192.168.1.101:8080/webservice/LoginWebservice?wsdl";


5、一些参考的网址(12月7日更新)

http://bbs.csdn.net/topics/390788599

这个是一个常见的报错,原因是服务器回传的不是xml,不能用ksoap2必须使用http发送post请求

http://stackoverflow.com/questions/16497553/i-get-an-error-the-import-org-ksoap2-transport-httptransportse-can-not-be-re

http://stackoverflow.com/questions/tagged/android-ksoap2?sort=frequent&pageSize=15

http://stackoverflow.com/questions/12430136/ksoap2-org-xmlpull-v1-xmlpullparserexception-expected-start-tag-error

http://blog.csdn.net/menhin/article/details/11955207

以上是一些错误异常分析



http://www.cnblogs.com/gzggyy/archive/2011/06/21/2086159.html

http://www.cnblogs.com/lanxuezaipiao/archive/2013/05/10/3072216.html

以上是如何使用http去调用服务端的例子


http://blog.csdn.net/pfe_nova/article/details/26147297

http://bbs.csdn.net/topics/390615324

http://www.cnblogs.com/shenliang123/archive/2012/07/05/2578586.html

http://blog.csdn.net/x605940745/article/details/16834127

以上是查看的文章



http://webservice.36wu.com/mapService.asmx

http://blog.csdn.net/lsvtogergo/article/details/21445783

常用的webservice服务

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值