2011-01-23 65 views
3

我知道有線程問題的ProgressDialog已經被問了很多次,但沒有一個解決方案似乎適用於我的項目。基本上我想要做的是這樣的: 1)當用戶點擊一個按鈕時,活動向服務器發送一個授權請求 2)當這樣做時ProgressDialog顯示爲 3)當響應來臨時我想解僱ProgressDialog和活動的讀取和解釋返回對象如何在Activity從Web服務請求SoapObject時實現ProgressDialog?

如果我: 1)設置線程以更新具有響應的應用程序字段,下一個方法(線程外)將引發一個NPE當訪問字段 2)如果我在Thread中包含下一個方法,則第二個方法將拋出一個'java.lang.RuntimeException:無法在未調用Looper.prepare()的線程中創建處理程序''

對不起了很長的文字,但我完全失去它在這個...我的代碼是某事像這樣:

public class XXX extends Activity implements OnClickListener { 

// (...) 
private SoapObject returnObject; 
private String response; 

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    // (...) 
     authProgressDialog = ProgressDialog.show(XXX.this, "", "Authenticating...", true, false); 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       authenticate(); // method that calls the API via SOAP 
       authenticateReal(); // method that handles the response 
      } 
     }).start(); 

     mHandler = new Handler() { 
      public void handleMessage(Message msg) { 
       super.handleMessage(msg); 
       switch (msg.what) { 
        case 10: 
         authProgressDialog.dismiss(); 
         break; 
       } 
      } 
     }; 
    } 
} 

public void authenticate() { 
    // API stuff (...) 
    AndroidHttpTransport aht = new AndroidHttpTransport(URL); 
    try { 
     aht.call(SOAP_ACTION, soapEnvelope); 
     returnObject = (SoapObject) soapEnvelope.getResponse(); 
     response = returnObject.getProperty("ResponseStatus").toString(); 
    } 
    catch (Exception e) { 
     e.printStackTrace(); 
    } 
    finally { 
     mHandler.sendEmptyMessage(10); 
    } 
} 

// Method that needs to access returnObject and reponse objects and 
// it is here where the NPE's or other exceptions are thrown 
public void authenticateReal() { 
// (...) 
} 
+0

我可能會錯過一些關於線程的完全基本的東西,因爲我從來沒有真正讀過它們的tbh ......對不起一個noobish q。 authenticateReal()的內容可以很容易地傳遞給autenticate()的try塊。 – TomaszRykala 2011-01-23 20:26:34

回答

8

您更好地使用AsyncTask(這是Android的樣子):

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    new TheTask().execute(); 
} 

private class TheTask extends AsyncTask<Void, Void, Void>{ 

    @Override 
    protected void onPreExecute() { 
     authProgressDialog = ProgressDialog.show(XXX.this, "", "Authenticating...", true, false); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     authenticate(); // method that calls the API via SOAP 
     authenticateReal(); // method that handles the response 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     authProgressDialog.dismiss(); 
    } 
} 

順便說...我發現這個演示是非常有用的(它談論REST的應用程序,但你可以將相同的理念,爲不同類型的應用程序):Developing Android REST client applications

+0

非常感謝。這已經解決了這個問題:) – TomaszRykala 2011-01-23 21:39:01

+0

這一個是非常有幫助 – Shijilal 2011-02-05 16:16:39

+0

正是我所需要的!謝謝!!如果沒有這個對話框,甚至不會顯示,直到執行完成,因爲它是異步的! – bluediapente 2011-03-31 14:36:59

2

爲了您的最後一個問題,把「 Looper.prepare();」進入你的run()方法。

 @Override 
     public void run() { 
      Looper.prepare(); 
      authenticate(); // method that calls the API via SOAP 
      authenticateReal(); // method that handles the response 
     } 

您是否檢查了您的authenticate()方法中的響應是否正常工作? (使用LogCat顯示響應)

否則,最好使用AsyncTask(如建議)。

1

如果你真的想使用Thread代替AsyncTask的你可以嘗試這樣說:

public class XXX extends Activity implements OnClickListener { 
... 
    private static int HANDLER_MESSAGE_AUTH_REQUEST_COMPLETE = 10; 
... 
    private void performAuthentication(){ 
     authProgressDialog = ProgressDialog.show(XXX.this, "", "Authenticating...", true, false); 
     Thread backgroundThread = new Thread() { 
      @Override 
      public void run() { 
       authenticate(); 
      } 
     } 
     backgroundThread.start(); 
    } 

    private Handler handler = new Handler(){ 
     @Override 
     public void handleMessage(Message msg) { 
      switch(msg.what){ 
      case HANDLER_MESSAGE_AUTH_REQUEST_COMPLETE: 
       authProgressDialog.dismiss(); 
       break; 
      } 
     } 
    } 

    private void authenticate(){ 
     // existing authenticate code goes here 
     ... 
     Message msg = Message.obtain(); 
     msg.what = HANDLER_MESSAGE_AUTH_REQUEST_COMPLETE; 
     handler.sendMessage(msg); 
     // existing authenticateReal code goes here 
     ... 
    } 
} 

從您的代碼,其中變量mHandler分配給new Handler()它不是100%清楚。要清楚,在我的代碼中,這應該是class本身的private字段。如果遇到錯誤,您還需要在您的authenticate()方法中使用一些錯誤處理來發送消息以關閉對話框。

1

正如其他人已經寫道,AsyncTask是繼續前進的方式。

BUT:的AsyncTask和線程對UI元素的一些缺陷:

如果你改變手機方向並沒有設置android:configChanges="keyboardHidden|orientation"爲您的活動(意味着你必須自己處理onConfigChange)在manifest.xml,方向更改會破壞並重新創建您的Activity和ContentView,並從可見窗口中斷開ProgressDialog(它連接到舊窗口)。 Android不會殺死你的Thread或AsyncTask。如果活動被破壞,它也不會殺死它。這些後臺任務將繼續,直到完成。

嘗試解除()您的預先創建的ProgressDialog在ContentView被銷燬後拋出異常,因爲它不再是您的窗口的一部分。在做某些分離(異步)工作的情況下嘗試/捕獲很多。當onPostExecute()被再次調用時,你可能依賴的所有東西都可能會消失或被不同的東西所取代。 最後考慮在你的Activity中註冊每個ASyncTask,並嘗試在你的Activity.onDestroy()中取消()它們。