Android WebService簡單教程與Source Not found異常解決方案

一、獲取並使用KSOAP包

在Android SDK中並沒有提供調用WebService的庫,因此,需要使用第三方的SDK來調用WebService。PC版本的WebService庫非常豐富,但這些對Android來說過於龐大。適合手機的WebService客戶端的SDK有一些,比較常用的是KSOAP2。

KSOAP2 地址:http://code.google.com/p/ksoap2-android/


二、添加SOAP到Android工程

下載後得到SOAP壓縮包將壓縮包解壓將JAR類型文件添加的到安卓工程具體步驟如下圖:


步驟一、

選擇我們的項目,右鍵菜單中 Build Path –> Add External Archives… 增加這個下載的JAR包


增加好後,我們在 選擇我們的項目,右鍵菜單中 Build Path –> Configure Build Path 的 Libraries 中可以看到下面圖我們下載的到的

ksoap2-android-assembly-2.5.4-jar-with-dependencies.jar已經被導入安卓工程。




步驟二、切換到Order and Export 的tab ,選擇在ksoap2-android-assembly-2.5.4-jar-with-dependencies.jar前的checkBox點擊OK。切記不要選擇Android4.x安卓自帶的庫否則運行也會執行出錯,如圖我沒有選擇Android 4,.3(具體原因目前尚未搞懂)


說完了整個環境的搭建,我們在來說說WebService 調用的步驟:

1、指定 WebService 的命名空間和調用方法

import org.ksoap2.serialization.SoapObject;

private static final String NAMESPACE = "http://WebXml.com.cn/";

private static final String METHOD_NAME = "getWeatherbyCityName";

 

SoapObject rpc = new SoapObject(NAMESPACE, METHOD_NAME);

SoapObject類的第一個參數表示WebService的命名空間,可以從WSDL文檔中找到WebService的命名空間

第二個參數表示要調用的WebService方法名。


2、設置調用方法的參數值,如果沒有參數,可以省略,設置方法的參數值的代碼如下:

rpc.addProperty("theCityName", "廣州");


3、生成調用Webservice方法的SOAP請求信息。

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

envelope.bodyOut = rpc;

envelope.dotNet = true;

envelope.setOutputSoapObject(rpc);

創建SoapSerializationEnvelope對象時需要通過SoapSerializationEnvelope類的構造方法設置SOAP協議的版本號。
該版本號需要根據服務端WebService的版本號設置。
在創建SoapSerializationEnvelope對象後,不要忘了設置SOAPSoapSerializationEnvelope類的bodyOut屬性,
該屬性的值就是在第一步創建的SoapObject對象。


4、創建HttpTransportsSE對象。

這裏不要使用 AndroidHttpTransport ht = new AndroidHttpTransport(URL); 這是一個要過期的類

private static String URL = "http://www.webxml.com.cn/webservices/weatherwebservice.asmx";

HttpTransportSE ht = new HttpTransportSE(URL);

ht.debug = true;


5、使用call方法調用WebService方法

private static String SOAP_ACTION = "http://WebXml.com.cn/getWeatherbyCityName";

ht.call(SOAP_ACTION, envelope);

第一個參數可以爲null,第2個參數就是在第3步創建的SoapSerializationEnvelope對象。


6、獲得WebService方法的返回結果

有兩種方法:

1、使用getResponse方法獲得返回數據。

private SoapObject detail;

detail =(SoapObject) envelope.getResponse();

2、使用 bodyIn 及 getProperty。

private SoapObject detail;

SoapObject result = (SoapObject)envelope.bodyIn;

detail = (SoapObject) result.getProperty("getWeatherbyCityNameResult");


7、訪問webService的主要代碼要寫在子線程中在安卓4.0平臺不允許直接在UI線程也就是Activity的主線程簡歷網絡連接、訪問網絡資源,因爲這些訪問通常是阻塞操作會影響到UI的流暢性這也是安卓4.0平臺以後的一個優化,因此爲了防止出現一些bug我們最好在子線程中進行webService訪問,通過handler將子線程消息返回到主線程中。


8、這時候不要忘記在改 AndroidManifest.xml 文件,添加網絡訪問權限

<uses-permission android:name="android.permission.INTERNET"></uses-permission>否則會執行出錯。

9、這時候你辛辛苦苦寫好所有主程序的時候,不斷地進行調試,不斷地發現Source Not Found這樣的異常程序崩潰,你往往會異常鬱悶和糾結懷疑是不是自己寫的程序不對,懷疑哪裏出現了空引用,是不是環境沒有搭建好,其實可能不是,

 

只是沒人提醒你在AndroidManifest.xml中要移除對sdk版本的限制,也下面的xml代碼:

<uses-sdk android:minSdkVersion="10"

        android:targetSdkVersion="18" />

完整的 AndroidManifest.xml 文件如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.weatherservice"
    android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.weatherservice.WeatherActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>


完整的Java代碼如下:

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

 

import android.os.Handler;

import android.os.Message;

 

import android.view.View;

import android.view.View.OnClickListener;

 

import org.ksoap2.*;

import org.ksoap2.serialization.SoapObject;

import org.ksoap2.serialization.SoapSerializationEnvelope;

import org.ksoap2.transport.HttpTransportSE;

import org.xmlpull.v1.XmlPullParserException;

import android.widget.*;

public class WeatherActivity extends Activity {

private static final String NAMESPACE = "http://WebXml.com.cn/";

private static String URL = "http://www.webxml.com.cn/webservices/weatherwebservice.asmx";

private static final String METHOD_NAME = "getWeatherbyCityName";

private static String SOAP_ACTION = "http://WebXml.com.cn/getWeatherbyCityName";

private String weatherToday;

private SoapObject detail;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_weather);

Button  button = (Button)findViewById(R.id.button1);

final Handler handler = new Handler()

      {

       public void handleMessage(Message msg)

       {

       if(msg.what==0x123)

       Toast.makeText(WeatherActivity.this, msg.obj.toString(), Toast.LENGTH_LONG).show();

      }

    };

button.setOnClickListener(new OnClickListener(){

@Override

public void onClick(View v) {

String city = "廣州";  

SoapObject rpc = new SoapObject(NAMESPACE,METHOD_NAME);

rpc.addProperty("theCityName", city);

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

envelope.bodyOut = rpc;

envelope.dotNet = true;

envelope.setOutputSoapObject(rpc);

HttpTransportSE ht = new HttpTransportSE(URL);

     getWeatherThread thread =new getWeatherThread(handler,ht,envelope);

     new Thread(thread).start(); 

}

});

}

 

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.weather, menu);

return true;

}

class getWeatherThread implements Runnable

private HttpTransportSE ht;

private Handler handler;

SoapSerializationEnvelope envelope;

     public getWeatherThread(Handler handler,HttpTransportSE ht,SoapSerializationEnvelope envelope)

     {

    

     this.handler = handler;

      this.ht = ht;

      this.envelope = envelope;

     }

@Override

public void run() {

ht.debug = true;

try {

ht.call(SOAP_ACTIONenvelope);

detail =(SoapObject) envelope.getResponse();

System.out.println("detail" + detail);

String weather = parseWeather(detail);

Message msg = new Message();

msg.obj  = weather;

msg.what =0x123;

handler.sendMessage(msg);

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

catch (XmlPullParserException e) {

// TODO Auto-generated catch block

e.printStackTrace();

     }

}

private String parseWeather(SoapObject detail)

throws UnsupportedEncodingException {

String date = detail.getProperty(6).toString();

weatherToday = "今天:" + date.split(" ")[0];

weatherToday = weatherToday + "\n天氣:" + date.split(" ")[1];

weatherToday = weatherToday + "\n氣溫:"

+ detail.getProperty(5).toString();

weatherToday = weatherToday + "\n風力:"

+ detail.getProperty(7).toString() + "\n";

 

return weatherToday;

}

}

}

Layout.xml省略

本文所參考資料:

Android調用天氣預報的WebService簡單例子 

http://www.cnblogs.com/ghj1976/archive/2011/04/26/2028904.html

 

紅色字體部分是本人在實驗過程中遇到的問題,希望大家可以吸取教訓。

本人水平有限希望同行高手發現錯誤不吝賜教,尚未解決的問題可以回答一二謝謝。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章