2011-11-26 45 views
1

我似乎在計時線程和對話窗口方面存在一致的問題。我試過使用線程或onCreate/onPrepare或AsyncTask在後臺執行一些下載/處理。通常,當後臺處理完成並解除對話窗口時,控制似乎返回到根線程(活動/ UI線程?)之前對話框消失或類似onPostExecute的過程完成。這讓我覺得我做錯了。下面是一個典型結構(僞代碼):無序多線程處理和對話框的Android問題

public class X { 
    protected String result = null; 
    protected ProgressDialog progressDialog; 

    public void onCreate() { 
    ... 
    new XTask().execute(); 
    progressDialog.show(); 
    // result is null here, should be "hi"? 

    // do things with result, like barf on a NPE...sigh 
    } 

    private class XTask extends AsyncTask { 
    protected doInBackground() { 
     // Get URL. 
     // Look at contents, takes a few seconds. 
     // Return the result (should get sent to onPostExecute). 
    } 
    protected onPostExecute(r) { 
     result = r; 
     progressDialog.dismiss(); 
    } 
    } 
} 

我認爲,後doPostExecute套導致和消除對話框,處理然後繼續在onCreate方法。但是,onCreate中的結果往往(並非總是)爲空。有一個更好的方法嗎?這是否只是由於模擬器的普遍興趣?

謝謝。

編輯:爲了更具體一些,我的任務(在doInBackground中)獲取一個URL並對響應做一些處理。這個過程需要1-3秒。然後,理論上,onPostExecute將X.result設置爲所提取的內容。我知道網址內容是有效的,而且迴應很好(非空)。問題是,在那1-3秒內,控制權返回到onCreate,就好像progressDialog根本沒有生存過(它根本不會顯示在模擬器中,但這是正常的)。

我以爲調用dialog.show()是一種阻塞方法,即出現對話框,並且該方法在它消失之前不會繼續,但似乎並非如此。或者我的progressDialog.dismiss()在之前被調用,它應該在設置X.result之前,或者根本沒有被調用,或者dismiss()在賦值之前更快/完成,否則完全是錯誤的。

更改execute和progressDialog的順序沒有幫助,也沒有將它移到onPreExecute()中。奇怪的是,onPostExecute不會被調用,直到我在onCreate返回。如果我在執行後有一個Thread.sleep循環(我認爲給它時間會有幫助),它將永遠不會完成任務,直到該循環結束並返回。例如:

new XTask().execute(); 
int z=0; 
while (response == null && z < 50) { 
    Thread.sleep(500); 
    z++; 
} 
if (response == null) return; 

任務的onPostExecute方法直到「返回」纔會被調用。嗯......也許正在onCreate正在影響它。

回答

0

我會在觸發AsyncTask之前顯示進度對話框。通常情況下,當一個AsyncTask被執行時,它需要一段時間才能完成,在那個時候,任務調用方法的其餘部分已經運行。但在你的情況下,任務立即返回,這可能是爲什麼在AsyncTask下調用postexecute之後對話框出現。

+0

我試過了,它沒有幫助。我的印象是,dialog.show()阻止了調用方法的繼續,但我猜不是(至少不是在「模擬器」中)。我更新了我的問題。感謝您的建議! – Josh

0

我會認爲,在doPostExecute設置結果並關閉對話框之後,處理將在onCreate方法中繼續。

這是不正確的,當你調用新XTask()。在UI線程中執行(),應用程序創建一個工作線程並開始運行任何你在AsyncTask.doInBackground()這方面的工作線程不顧,在這(在調用新的XTask()。execute()之後),UI線程繼續執行新的XTask()。execute()之後的代碼。

您談論的問題是您的工作線程完成並返回到UI線程的位置是AysncTask.onPostExecute(),此方法保證在AsyncTask完成後在UI線程上調用。這就是它被稱爲AsyncTask的原因。UI線程和工作線程都是異步運行的。

如果你想使你的UI線程阻塞和XTask後等待的AsyncTask完成()執行(),你可以這樣:

XTask xTask = new XTask(); 
xTask.execute(); 
progressDialog.show(); 
xTask.get() // <-- this will make your UI thread blocked and wait for AsycnTask at this point 
// result is null here, should be "hi"? 

這是可能的,但不是一個好的做法,如AsyncTask.get()會阻塞執行調用線程,所以可能會得到ANR異常。

綜上所述
1. AysncTask.onPostExecute()是從工作線程UI線程進程回報,我們不關心,當它將在UI線程調用,我們只需要確保這將是將來會在某個時候正確調用UI線程。
2. AsyncTask.get()通過調用此方法實際上使AsyncTask與調用線程同步運行。

+0

我明白,execute()啓動一個新的線程。我認爲對話框會停止處理,但它不會。但是,onPostExecute()的作品,謝謝。不知道我是如何錯過的。 – Josh

1

ProgressDialog通常用於阻止加載或繁重處理期間的用戶交互,但主UI線程將繼續執行。

如果您希望對結果執行一些操作,您必須在XTask的onPostExecute中執行此操作,或者在doInBackground中獲得結果後執行此操作。

private class XTask extends AsyncTask { 

    @Override 
    protected void onProgressUpdate(/*params*/){ 
      //modify UI 
    } 
    protected doInBackground() { 
    // Get URL. 
    // Look at contents, takes a few seconds. 

    //Option A: Now have the result, do some other processing here 
    //Cant modify UI components from here, If you need to modify a UI component from   
    //here call publishProgress() and modify the component in onProgressUpdate() 

    // Return the result (should get sent to onPostExecute). 
} 
protected onPostExecute(r) { 

    result = r; 
    //Option B do some processing on the result 
    //You can modify UI components from here 
    progressDialog.dismiss(); 
} 

}

+0

在PostExecute作品上使用。我以爲我嘗試過,但沒有,但我再次嘗試,似乎......謝謝。 – Josh

0

把代碼放到任務的onPostExecute應該工作,一個簡單的測試表明,它會(對我來說)。但是,我最終寫了一個也適用的不同解決方案。我將大部分代碼放入活動的Handler中,將其與UI線程完全分開。我的onCreate只是顯示加載ProgressDialog窗口,就是它 - 它只是坐在那裏,「加載」。後臺任務完成它的任務,完成後,將消息發送給處理程序。該消息告訴處理程序關閉加載對話框並填充列表。如果有錯誤,則發送不同的消息,處理程序顯示錯誤對話框。