Android調用Web服務

来源:http://www.cnblogs.com/mingjiatang/archive/2016/10/28/6007559.html
-Advertisement-
Play Games

現在大部分應用程式都把業務邏輯處理,數據調用等功能封裝成了服務的形式,應用程式只需要調用這些web服務就好了,在這裡就不贅述web服務的優點了。本文總結如何在android中調用Web服務,通過傳遞基類型和複雜類型對比調用.NET平臺發佈的WCF服務和WebService服務之間的區別。 0 寫在前 ...


現在大部分應用程式都把業務邏輯處理,數據調用等功能封裝成了服務的形式,應用程式只需要調用這些web服務就好了,在這裡就不贅述web服務的優點了。本文總結如何在android中調用Web服務,通過傳遞基類型和複雜類型對比調用.NET平臺發佈的WCF服務和WebService服務之間的區別。

0 寫在前面

以前都是在.NET平臺上conding,使用.NET平臺發佈服務,然後再在.NET的客戶端進行調用,非常的方便,最簡單的方式就是添加web服務引用,通過添加web服務引用實現像本地調用那樣調用web服務,當然我們也可以採用http-post、http-get和基於soap協議的方式去調用服務。

最近在弄andriod的程式,需要調用web伺服器上的數據,服務採用C#寫的,並部署在iis伺服器上。我們可以像.NET那樣調用服務那,利用andriod庫自帶的HttpPost和HttpGet類來調用Web服務。但是wcf服務發佈的一些沒有添加WebGet或者WebInvoke特性的服務,都只提供基於Soap協議的服務調用方式。雖然soap協議也是基於Http協議,也可以使用HttpPost類來進行調用,但拼湊soap結構體是比較麻煩,好在Ksoap2包提供了調用web服務的方法,而且還比較好的相容了.NET平臺發佈的服務。因此本文總結在Andriod中如何使用Ksoap2來調用.NET平臺的服務,通過傳遞基類型和複雜類型對比調用.NET服務發佈的WCF服務和WebService服務之間的區別。本文的末尾提供Ksoap2包的下載。

1 WCF服務

我們在服務中提供兩個方法,一個計算整數加法,另一個接受People對象並且返回People信息(string)。

1.1 People的數據契約

[DataContract]
public class People
{
  [DataMember]
  public int Age;
  [DataMember]
  public string Name;
}

2.2 WCF服務契約

[ServiceContract(Name = "JuameService", Namespace = "http://www.juame.edu")]
public interface ITest
{
    [OperationContract]
    int Add(int op1, int op2);

    [OperationContract]
    string PostPeopleInfo(People people);

}

上面的服務契約設置了Namespace特性,該特性重要。在後面的wb服務調用中需要用到。

2.3 WCF服務實現

public class TestService : ITest
{
    public int Add(int op1, int op2)
    {
        return op1 + op2;
    }

    public string PostPeopleInfo(People people)
    {
        return "姓名:"+people.Name+"/"+"年齡"+people.Age;
    }
}

我們需要把服務部署到IIS中去,因此需要添加一個svc文件,把服務實現的代碼寫在svc文件中,發佈後,服務調用的地址就是svc文件的地址。

2.4 服務配置

<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- 為避免泄漏元數據信息,請在部署前將以下值設置為 false -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- 要接收故障異常詳細信息以進行調試,請將以下值設置為 true。在部署前設置為 false 以避免泄漏異常信息 -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
       <service name="Juame.Service.TestService">
        <endpoint address="" 
                  binding="basicHttpBinding"
                  contract ="Juame.Service.ITest">          
        </endpoint>
      </service>
    </services>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        若要在調試過程中瀏覽 Web 應用程式根目錄,請將下麵的值設置為 True。
        在部署之前將該值設置為 False 可避免泄露 Web 應用程式文件夾信息。
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

主要是配置好Service節點和serviceBehaviors就行,服務採用BasicHttpBinding類型。在這裡多提一點。BasicHttpBinding是針對於Soap Web Service協議,而webHttpBinding支持web service協議,因此在wcf服務上加上WebGet或WebInvoke特性的必須要使用webHttpBinding類型。

在iis中發佈web服務非常簡單和部署asp.net網站一樣,服務發佈成功之後,能訪問到svc的地址。

2016_10_6798d44e-3b10-4b21-9b40-66d024199b2f

我們提供的服務,一個是傳遞基類型(string,int,float等),另外一個是傳遞對象(複雜類型)。

2 Android調用WCF服務

2.1 android佈局

界面佈局非常簡單,兩個Button,一個TextView,按鈕分別用來調用兩個服務,而TextView用來顯示服務調用的結果。

<LinearLayout 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:orientation="vertical"
    tools:context="com.example.soapprousage.MainActivity" >

    <Button android:id="@+id/btn_jlx"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="基類型調用"/>
    <Button android:id="@+id/btn_obj"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="對象調用"/>
    <TextView android:id="@+id/lbl_result"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
       android:textAlignment="viewStart"/>"
</LinearLayout>

2.2 利用Ksoap2調用wcf服務

首先把下載下來的Jar格式的Ksoap包複製到libs(自己創建)文件夾下。

聲明服務調用需要的地址和方法

private String nameSpace="http://www.juame.edu";//和wcf服務契約特性的Namespace是一樣的
private String url="http://172.21.212.54:8888/TestService.svc";//svc服務地址
private String soapAction="http://www.juame.edu/JuameService/Add";//操作地址
private String methodName="Add";//方法名稱

上面聲明的服務地址、命名空間、操作地址和方法名稱都可以從服務的wsdl文檔中查看,

2016_10_bab1b9f2-cb82-4092-a3e3-e3fc133b4186

下麵利用ksoap2對服務進行調用的代碼如下。

protected SoapObject getSoapResult(int op1,int op2){
    SoapObject outObject=new SoapObject(nameSpace,methodName);
    //添加輸出參數
    outObject.addProperty("op1", op1);
    outObject.addProperty("op2",op2);
    
    SoapSerializationEnvelope serializationEnvelope=new SoapSerializationEnvelope(SoapEnvelope.VER11);//設置soap版本
    
    serializationEnvelope.bodyOut=outObject;
    serializationEnvelope.dotNet=true;//調用.NET的服務
    
    HttpTransportSE transportSE=new HttpTransportSE(url);
    transportSE.debug=true;//採用調試

    try{
        transportSE.call(soapAction, serializationEnvelope);//調用服務
        SoapObject result=(SoapObject)serializationEnvelope.bodyIn;//獲取調用結果
        Log.v("happy1", "服務調用成功");
      //把結果封送到消息中去,讓ui線程顯示
        Bundle bundle=new Bundle();
        bundle.putString("result", result.getProperty(0).toString());//獲取結果中的值
        Message message=new Message();
        message.setData(bundle);
        message.what=12;
        hander.sendMessage(message);
        return result;
        
    }catch(IOException ex){
        Log.v("sad", "IO異常");
        ex.printStackTrace();
    }catch(XmlPullParserException ex){
        Log.v("sad", "xml解析異常");
        ex.printStackTrace();
        
    }catch(Exception ex){
        Log.v("sad", "服務調用異常異常");
    }   
    return null;
}

按鈕事件代碼,採用多線程。在android3.0後,有關網路資源的調用代碼都不能直接在主UI線程中調用,否則會出現android.os.NetworkOnMainThreadException異常。關於android中的多線程機制有時間再進行總結。

//綁定按鈕事件
btnJlx.setOnClickListener(new OnClickListener() {
    
    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
        Thread thread=new Thread(getSoapRequest);
        thread.start();
    }
});
//線程
Runnable getSoapRequest=new Runnable() {
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        getSoapResult(10, 20);
    }
};
//消息處理
Handler hander = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if(msg.what=12){
            lblResult.append(msg.getData().getString("result")+"\r\n");
        }
    }
};

到目前為止,我們已經調用了wcf服務第一個服務,就說明傳遞基類型是沒有問題。但是很遺憾的是,對於傳遞複雜類型和數組集合參數進行調用,在服務那邊總是提示無法對傳遞進來的數據進行反序列化的錯誤(希望高手指點)。還好我們可以把所以的服務類型都轉為json數據,通過json數據進行傳遞調用,就可以解決複雜類型傳遞的問題。

對於有強迫症的我來說,不甘心,因為在網上看了許多的教程,利用Ksoap2是可以直接傳遞複雜類型的來調用.NET平臺的服務的。不過網上大部分教程調用的都是傳統的webservice服務(asmx文件),於是我就在wcf服務項目中新建一個傳統的asmx文件,提供的服務與wcf服務一樣的。結果發現,果然能夠利用ksoap2傳遞一個複雜類型來調用服務。下一節總結利用ksoap2傳遞複雜對象來調用傳統的webservice服務。

3 傳統的WebService服務

為了和wcf服務進行對比,webservice提供的服務和wcf一致,代碼如下:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允許使用 ASP.NET AJAX 從腳本中調用此 Web 服務,請取消註釋以下行。 
// [System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService
{
    [WebMethod]
    public int Add(int op1, int op2)
    {
        return op1 + op2;
    }
    [WebMethod]
    public string PostPeopleInfo(People people)
    {
        return "姓名:" + people.Name + "/" + "年齡:" + people.Age; 
    }
}

其中WebService特性中的Namespace屬性和wcf的Namespace的作用一樣的。

同樣的也在iis中進行發佈。發佈成功之後,能夠訪問到asmx文件。

4 Android調用WebService服務

不管是調用WCF的服務還是WebService的服務,傳遞基類型去調用,代碼都是一樣的,且能夠正確的調用。下麵利用複雜的People類型來調用WebService的服務。

我們需要傳遞複雜類型,首先我們要在android中建立一個複雜類型,並且複雜類型包含欄位名稱和個數一定要與服務上的複雜類型保持一致,對於服務的複雜類型具有哪些欄位,我們可以通過查看服務調用的示例得知。如下圖所示。

2016_10_485cf694-7bf4-409c-9074-a849cc9cb329

根據上面複雜類型的欄位說明,我們在android中建立複雜類型(類型名可以隨意),包含兩個欄位且欄位名稱必須是Age和Name,數據類型也要一致,上面的這個people代表該複雜類型形參名為people(服務調用的時候必須要保持一樣)。需要註意的是,這個複雜類型必須要繼承KvmSerializable,這樣ksoap2進行服務調用的時候,能夠把people對象序列化為服務端能夠接受的格式。代碼如下:

public class People implements KvmSerializable {      
    public int Age;  
    public String Name;  
    @Override  
    public Object getProperty(int arg0) {           
        switch (arg0){  
            case 0:  
                return Age;  
            case 1:  
                return Name;  
            default:  
                return null;  
        }  
    }  
   
    @Override  
    public int getPropertyCount() {  
        return 2;  
    }  
  
    @Override  
    public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) {           
        switch (arg0){  
            case 0:{  
                arg2.type = PropertyInfo.INTEGER_CLASS;  
                arg2.name = "Age";  
                break;
            }  
            case 1:{  
                arg2.type = PropertyInfo.STRING_CLASS;  
                arg2.name = "Name";  
                break;
            }  
        }          
    }  
    
    @Override  
    public void setProperty(int arg0, Object arg1) {           
        switch (arg0){  
            case 0:{  
                Age = Integer.parseInt(arg1.toString()) ;  
                break;
            }  
            case 1:{  
                Name = arg1.toString();  
                break;
            }  
        }   
    }  
}   

下麵是傳遞複雜對象調用web服務,其中服務地址、操作地址、方法名以及命名空間和前面一樣,只需要在服務說明wsdl文檔中找operation name節點和operation soapAction節點的值即可,其他地方也類似,只是在封裝soapobject的時候有一些區別,代碼如下:

//地址聲明
private String nameSpace="http://tempuri.org/";
private String url="http://172.21.212.54:8888/WebService.asmx";
private String soapAction="http://tempuri.org/PostPeopleInfo";
private String methodName="PostPeopleInfo";

//服務調用
protected SoapObject getSoapResult() {
    SoapObject outObject = new SoapObject(nameSpace, methodName);

    People people = new People();
    // 設置欄位值
    people.setProperty(0, 23);
    people.setProperty(1, "Juame");

    // 設置SoapObject對象
    outObject.addProperty("people", people);
    //也可以這樣設置SoapObject
    /*PropertyInfo peoInfo = new PropertyInfo();    
    peoInfo.setName("people");    
    peoInfo.setValue(people);
    peoInfo.setType(People.class); 
    outObject.addProperty(peoInfo);*/
  
    SoapSerializationEnvelope serializationEnvelope = new SoapSerializationEnvelope(
            SoapEnvelope.VER11);//設置soap版本
    // 這一步添加映射非常關鍵
    // 第一個參數為命名空間,第二參數為伺服器中複雜類型的名稱,第三參數是安卓的複雜類型
    serializationEnvelope.addMapping(nameSpace, "People", People.class);

    serializationEnvelope.bodyOut = outObject;
    serializationEnvelope.dotNet = true;// 調用.NET的服務

    HttpTransportSE transportSE = new HttpTransportSE(url);
    transportSE.debug = true;// 採用調試

    try {
        transportSE.call(soapAction, serializationEnvelope);// 調用服務
        Log.v("happy1", "服務調用成功");
        SoapObject result = (SoapObject) serializationEnvelope.bodyIn;
       //把結果封送到消息中去,讓ui線程顯示
        Bundle bundle = new Bundle();
        bundle.putString("result",result.getProperty(0).toString());
        Message message = new Message();
        message.setData(bundle);
        message.what = 11;
        hander.sendMessage(message);
        return result;

    } catch (IOException ex) {
        Log.v("sad", "IO異常");
        ex.printStackTrace();
    } catch (XmlPullParserException ex) {
        Log.v("sad", "xml解析異常");
        ex.printStackTrace();

    } catch (Exception ex) {
        Log.v("sad", "服務調用異常異常");
    }

    return null;
}
//按鈕事件
btnObj.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub       
        Thread thread = new Thread(getSoapRequest);
        thread.start();
    }
});
//線程
Runnable getSoapRequest=new Runnable() {
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        getSoapResult();
    }
};
//消息處理
Handler hander = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if(msg.what=11){
            lblResult.append(msg.getData().getString("result")+"\r\n");
        }
    }
};

上面的代碼就能夠傳遞複雜類型去調用WebService的服務,返回結果如下:

姓名:Juame/年齡:23

5 簡述Wcf與WebServic的區別

WebService是一個行業標準,也是Web Service的規範,既不是框架,也不是技術,它使用xml擴展標記語言來表示數據,這正是WebService能夠跨語言和平臺的關鍵,而微軟的Web服務實現稱為ASP.NET Web Service.它使用Soap簡單對象訪問協議來實現分散式環境里應用程式之間的數據交互。

WCF 是一個分散式應用的開發框架,屬於特定的技術,或者平臺。既不是標準也不是規範。在一定程度上就是WebService,不得不說WCF確實非常方便,提供非常多且好用的特性,可以用來創建各種服務,而且自定義性也高,以後項目的服務搭建都會基於WCF來實現。

6 小結

本文總結瞭如何使用android調用web服務。在傳遞複雜類型調用服務的時候糾結的了半天,最後實現了傳遞複雜類型調用WebService服務,但沒有實現對WCF服務的調用,而傳遞基類型調用服務,兩者都可以。在第5小節中還簡述了wcf和webservice之間的區別,其實在項目大都是採用wcf框架來發佈自己的服務。下麵會繼續總結如何用javascript來調用wcf發佈的服務。

另Ksaop2下載鏈接:http://download.csdn.net/download/mingge38/9666650


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • button的點擊效果無疑是非常簡單的,以致於我懶到當UI告訴我說在點擊的時候button字體的顏色也要隨著背景改變的時候我毫不猶豫的告訴他讓他切兩個圖過來,後來想想著實是不太靠譜,於是瞭解了一下如何添加button點擊的字體顏色變化效果。 1.首先你要在你的color文件下加入幾個你需要的色值,註 ...
  • 1:iOS項目配置文件info.plist文件解析 2:iOS最新的許可權設置 3:關於openURL 蘋果在iOS 2中引入了openURL:方法來進行APP間的跳轉。不過在iOS 9中,相關的canOpenURL在iOS 10中,蘋果已棄用了openURL,轉而用openURL:options:c ...
  • MenuPopwindow: 1 package com.cloudeye.android.cloudeye.view; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.graph ...
  • Android Studio常用快捷鍵 Android Studio日常開發常用快捷鍵. 快捷鍵版本: Mac OS X 10.5+ 搜索查看類 | 用途 | Mac快捷鍵 | |: |: | | 搜索所有文件 | double Shift | | 搜索文件 | Cmd + Shift + O | ...
  • 實現的效果比較簡單類似於微信打開網頁,頭部有個進度條顯示載入進度 下載地址:http://download.csdn.net/detail/qq_29774291/9666941 1.在安卓端載入一個網頁 2.顯示網頁開始載入和載入的進度;不過在有時會出現onPageStarted等多次調用的情況, ...
  • 前幾天將我的Xcode升到了8,但是在運行程式時,會列印很多沒有用的信息,如下圖: Xcode8運行程式時列印的亂碼 Xcode8運行程式時列印的亂碼 於是各種尋求答案,找到如下答案: Edit Scheme-> Run -> Arguments, 在Environment Variables裡邊添 ...
  • 本文是轉載的,轉載地址: "大白話解釋Strategy模式和State模式的區別" 先上圖: 本質上講,策略模式和狀態模式做得是同一件事:去耦合。怎麼去耦合?就是把乾什麼(語境類)和怎麼乾(策略介面)分開,互不依賴。打個比方,下麵是我一天的行程: 但問題來了,啪啪啪是個技術活,有著名的48式,今天到 ...
  • 如今,隨著信息技術的不斷發展,很多公司採用微信企業號來進行企業與員工之間的聯繫。其實微信企業號中右很多獨立的應用。 那麼如何可以將報表系統集成到微信中呢?這裡分享一下在微信企業號中創建獨立的報表應用,並且將微信賬號單點登錄到帆軟報表軟體FineReport的許可權對接。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...