Android平臺調用Web Service:引入線程

接上文

遺留問題

MainActivity的onCreate方法中如果沒有有這段代碼:

// 強制在UI線程中操作
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
       .detectDiskReads().detectDiskWrites().detectNetwork()
        .penaltyLog().build());
           
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
       .detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath()
        .build());

 

會報錯誤如下:

FATAL EXCEPTION:main

java.lang.NullPointerException

atcom.example.demoservice.MainActivity.getRemoteInfo(MainActivity.java:91)

atcom.example.demoservice.MainActivity$1.onClick(MainActivity.java:51)

 

這是因爲android 3.0+以上 已經不建議在activity中添加耗時操作,要界面和數據脫離。4.0以上的通信都必須放到線程裏去做不能在UI線程。解決辦法另起線程如果一定要想在UI線程操作,就需要添加如代碼

 

顯然這樣做是不可取的,因爲通信消耗時間長,可能會讓用戶傻傻的等待,那麼接下來就通過引入線程來解決這個問題。


通過Runnable接口和Thread類創建線程

我們可以用Runnable接口和Thread類創建線程,從而捨棄強制使用UI主線程的方式,代碼如下(同時對代碼進行了整理,把nameSpace等變量抽出來)

public classMainActivity extends Activity { 
 
    public static final String TAG ="webService_pj";
   
    private EditText phoneSecEditText; 
    private TextView resultView; 
    private Button queryButton; 
 
    @Override 
    public void onCreate(BundlesavedInstanceState) { 
           
//           StrictMode.setThreadPolicy(newStrictMode.ThreadPolicy.Builder()
//       .detectDiskReads().detectDiskWrites().detectNetwork()
//        .penaltyLog().build());
//           
//    StrictMode.setVmPolicy(newStrictMode.VmPolicy.Builder()
//       .detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath()
//        .build());
   
       super.onCreate(savedInstanceState); 
       setContentView(R.layout.activity_main); 
 
        phoneSecEditText = (EditText)findViewById(R.id.phone_sec); 
        resultView = (TextView)findViewById(R.id.result_text); 
        queryButton = (Button)findViewById(R.id.query_btn); 
 
        queryButton.setOnClickListener(newOnClickListener() { 
            @Override 
            public void onClick(View v) { 
         
                   Log.i(TAG,"MainActivity線程ID:"+Thread.currentThread().getId());
 
                // 手機號碼(段) 
                String phoneSec =phoneSecEditText.getText().toString().trim(); 
                // 簡單判斷用戶輸入的手機號碼(段)是否合法 
                if("".equals(phoneSec) || phoneSec.length() < 7) { 
                    // 給出錯誤提示 
                   phoneSecEditText.setError("您輸入的手機號碼(段)有誤!"); 
                   phoneSecEditText.requestFocus(); 
                    // 將顯示查詢結果的TextView清空 
                   resultView.setText(""); 
                    return; 
                } 
               
                // 命名空間 
                String nameSpace = "http://WebXml.com.cn/"; 
                // 調用的方法名稱 
                String methodName ="getMobileCodeInfo"; 
                // EndPoint 
                String endPoint = "http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx"; 
                // SOAP Action 
                String soapAction = "http://WebXml.com.cn/getMobileCodeInfo";
                // method params and values
                ArrayList<String> params= new ArrayList<String>();
                ArrayList<Object> vals =new ArrayList<Object>();
               params.add("mobileCode");
                params.add("userId");
                vals.add(phoneSec);
                vals.add("");
               
                // 通過Runnable接口和Thread類 創建線程調用WebService
                   newMyThread(nameSpace,methodName,endPoint,soapAction,
                                                           params,vals).start();
                       //將WebService返回的結果顯示在TextView中 
                   resultView.setText(getResult());
 
            } 
        }); 
    } 
 
 
  
   
//通過Runnable接口和Thread類,得到線程返回值
privateString result;
 
publicString getResult(){
returnresult;
}
 
    private class MyThread extends Thread
{
 
    private String nameSpace;
    private String methodName;
    private String endPoint;
    private String soapAction;
        private ArrayList<String> params;
        private ArrayList<Object> vals;
       
    public MyThread(String nameSpace,  String methodName,
                   StringendPoint, String soapAction, ArrayList<String> params,ArrayList<Object> vals){ 
        this.nameSpace = nameSpace;
        this.methodName = methodName;
        this.endPoint = endPoint;
        this.soapAction = soapAction;
        this.params = params;
        this.vals = vals;
    } 
   
@Override
publicvoid run()
{
Log.i(TAG,"MyService線程ID:"+Thread.currentThread().getId());
result= getRemoteInfo(nameSpace, methodName, endPoint,
                                soapAction,params,vals);
}
 
}
   
      
    /**
     *@MethodName        : getRemoteInfo
     *@Description        : 調用遠程webservice方法
     * @param nameSpace
     * @param methodName
     * @param endPoint
     * @param soapAction
     * @param params
     * @param vals
     * @return
     */
    public String getRemoteInfo(StringnameSpace,  String methodName,
                                   StringendPoint, String soapAction, ArrayList<String> params,
                                   ArrayList<Object>vals) { 
 
 
        // 指定WebService的命名空間和調用的方法名 
        SoapObject rpc = newSoapObject(nameSpace, methodName); 
 
        //設置需調用WebService接口需要傳入的兩個參數mobileCode、userId 
        for (int i = 0; i < params.size();i++) {
rpc.addProperty(params.get(i),vals.get(i));
}
 
 
        //生成調用WebService方法的SOAP請求信息,並指定SOAP的版本 
        SoapSerializationEnvelope envelope =new SoapSerializationEnvelope(SoapEnvelope.VER10); 
 
        envelope.bodyOut = rpc; 
        // 設置是否調用的是dotNet開發的WebService 
//        envelope.dotNet = true; 
        // 等價於envelope.bodyOut = rpc; 
        envelope.setOutputSoapObject(rpc); 
 
        HttpTransportSE transport = newHttpTransportSE(endPoint); 
        try { 
            // 調用WebService 
            transport.call(soapAction,envelope); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
 
        // 獲取返回的數據 
        SoapObject object = (SoapObject)envelope.bodyIn; 
       
        String result = "";
        if (object != null) {
               // 獲取返回的結果 
               result =object.getProperty(0).toString(); 
        }
 
        return result;
    } 
} 


 

通過線程進行通信,得到同樣結果



出現新的問題

可以發現,執行線程中需要在線程中返回一個值,通過在run()中保存返回值,存儲返回值的變量應該是MainActivity的成員變量,然後在主線程中用一個get方法取得該值。

但是run何時完成是未知的,很可能當第一次點擊按鈕後,依然看不到結果,直到第二次或者更多纔看到,所以我們需要一定的機制來保證。

 

而在Java se5就開始用Callable和Future來管理多線程了,可以解決這個問題,接下文。。。


源碼下載

http://download.csdn.net/detail/tcl_6666/7365341


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