近段時間終於全面向Android平台進軍,但是在進入的時候,的確遇到很多問題,即使在調用WebService也遇到了不少的問題,在一番系統的學習過後,終於明白了個大概,現將學習的心得寫下,與所有跟我一樣剛入門的菜菜分享。
本人開發環境為Android Studio,如用Eclipse的童鞋請參照參照。
■下載 ksoap2-android 包
去http://code.google.com/p/ksoap2-android/wiki/HowToUse?tm=2下載最新版的“ksoap2-android”,我現時使用的版本為:“ksoap2-android-assembly-3.0.0-RC.4-jar-with-dependencies.jar”
■引用包
下載後,將類庫復制到“libs” 文件下。如果Eclipse的童鞋到這里引用就完事了,但於Android Studio的就還沒有完,因為Android Studio使用的是gradle,故還需要對引用進行聲明。找到build.gradle文件(於項目的底部),打開於dependencies節點里,添加代碼:
dependencies { compile 'com.android.support:support-v4:13.0.+' //添加以下代碼以聲明類庫的引用 compile files('libs/ksoap2-android-assembly-3.0.0-RC.4-jar-with-dependencies.jar') }
下面開始我以一個登錄的例子來講解整個webserive的調用過程
layout_login中有兩個EditText控件,一個按鈕,登錄界面最基本的配置。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center|center_horizontal|center_vertical" android:orientation="vertical" android:background="#6AA7D2"> <LinearLayout android:id="@+id/Layout_Input" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="15dp" android:layout_marginBottom="0dp" android:orientation="vertical"> <EditText android:id="@+id/Txt_Name" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" android:hint="用戶名" /> <EditText android:id="@+id/Txt_Password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:hint="密碼" /> </LinearLayout> <LinearLayout android:id="@+id/Layout_Button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp"> <Button android:id="@+id/Btn_Login" android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="登錄" android:onClick="Btn_Login_OnClick" /> </LinearLayout> </LinearLayout>
當點擊登錄Button時,執行以下事件
public void Btn_Login_OnClick(View view) { loginName = ControlHelper.GetText(this, R.id.Txt_Name); loginPassword = ControlHelper.GetText(this, R.id.Txt_Password); if (loginName.equals("")) { MessageHelper.AlertDialog(this, "操作提示","用戶名不能為空.")); findViewById(R.id.Txt_Name).requestFocus(); return; }
view.setEnabled(false); progressDialog = ProgressDialog.show(this,"Loading...","Please wait...",true,false); Thread thread = new Thread(new Runnable() { @Override public void run() { SystemClock.sleep(1000); Login(loginName, loginPassword); } }); thread.start(); }
說明:由於Android4.0以後主線程為了線程安全,訪問網絡不能由主線程進,只能由子線程訪問,另外像.net的winform一樣,子線程不能控制UI,所有的UI都必需由主線程控制,所以所有的什麽提示框,等候框都必需由主線程去操作。所以上面的代碼中,Login的方法是在新開的子線程中完成的。
而Runnable就是一個Thread要實現的接口,此接口中有一個run()方法,當線程執行start()方法時,就會自動調用Thread的Runnable接口中的run()方法。所以我們要子線程執行的所有代碼都在run()里完成。
順帶一提的就是,子線程讀取UI上控件的值是沒有限制的,所以如果想在子程線中讀取UI,直接讀取就可以了。
但於子線程又是怎樣跟主線程溝通的呢?這就要提到另外兩個東東就是Handler跟Message了。
下面先看一看Login方法里面的代碼
private void Login(String name,String psw) { Message msg = new Message(); try {
//聲明Service的空間命名,.net默認為 http://tempuri.org/
//第二個參數是要調用的方法 SoapObject so = new SoapObject(this.getString(R.string.webservice_namespace), "Login");
//設置調用Service需要傳入的兩個參數,聞說參數名可以不正確,但順序必需要正確 so.addProperty("accountName", name); so.addProperty("password", psw);
// 設置調用WebService方法的SOAP請求信息,並指定SOAP的版本 SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER12); envelope.bodyOut = so;
// 設置是否調用的是dotNet開發的WebService envelope.dotNet = true;
// 設置Service所使用的URL String url = this.getString(R.string.webservice_domain) + this.getString(R.string.webservice_url_logic); HttpTransportSE ht = new HttpTransportSE(url); ht.call(null, envelope); if (envelope.getResponse()!=null) {
//接收返回的對象 SoapObject responseSO = (SoapObject)envelope.getResponse(); Boolean succeed = Boolean.parseBoolean(responseSO.getProperty("Succeed").toString()); if(!succeed) { msg.obj = responseSO.getProperty("Message").toString(); msg.what = 0; } else { msg.obj = responseSO.getProperty("ReturnObject"); msg.what = 1; } } } catch (Exception ex) { msg.obj = ex.getMessage(); msg.what = -1; } finally { handler.sendMessage(msg); } }
我先講講我們的ksoap2是如何使用,再去講解Message與Handler。
上面的注釋都寫得很清楚了,在這里我提一提,在獲取接收的對象時,有兩種方法:
1. envelope.bodyIn
2.envelope.getResponse();
我選用的是第二種方法,因為我發現可以很好轉換回一個SoapObject,可能bodyIn都可以,但我沒有深入的研究,沒有發言權,有興趣又好學的同學們可以研究一下,記得研究完跟我說一聲。
別外值得一提如果你的Service返回的是一個對象,在ksoap2里,你的對象依然是一個SoapObject,你必須要寫代碼自已轉換,後面我還會有文章另外介紹。
下面再講如何,通知主線程,我所獲取得的返回結果了,大家看到,於Login方法中一開始就定義了一個Message的對象,其實這個對象就是用於線程之間通訊所使用的,姑且先這樣理解。
他有一個obj的屬性與一個what的屬性,obj用於存放通訊的數據,what是用於存放一個標志,為什麽需要這個標志呢?因為你Message可能有好多種狀態情況,what就是為了區分這些狀態而存在,如果你還是有不明白的,可能看了以下的代碼,或許會對你的了解有所幫助。
Handler接收Message
private Handler handler = new Handler(){ @Override public void handleMessage(Message msg){ findViewById(R.id.Btn_Login).setEnabled(true); progressDialog.dismiss(); switch (msg.what) { case -1: //exception MessageHelper.AlertDialog(Activity_Main.this, "異常提示", msg.obj.toString()); break; case 0: //fail MessageHelper.AlertDialog(Activity_Main.this, "錯誤提示", msg.obj.toString()); break; case 1: //login success MessageHelper.AlertDialog(Activity_Main.this, "操作提示", "登錄成功。");
break;
default: break; } } };
最後是需要在activity中定義一個Handler對象,並實現handleMessage的方法就可以。這樣整個調用Webservice的過程就完成了。
但是這里面還差一點小小的動作,就是由於你的程序未聲明網絡訪問的權限,所以無法接入網絡,並且有異常被拋出,聲明方法是,只需要在AndroidManifest.xml中聲明就可以了。
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="16" /> <!--添加以下節點聲明網絡使用--> <uses-permission android:name="android.permission.INTERNET" />
OK,你的調用webservice的程序就可以正常運行了。