2013-06-03 77 views
2

所以我有這些長期運行的服務器調用,基本上是在我的Android應用程序中進行的OData。這些調用的使用者使用.execute().get()來等待來自網絡線程的響應(我知道正確的方法是使整個事物成爲異步和基於回調的,但是沒有這些數據,應用程序將無法以任何方式運行,並且完全重新構建它以這種方式工作似乎沒有提供任何好處)。Android中的ProgressDialog AsyncTask沒有在正確的時間顯示

所以我發現很多片段在網上,其中聯合使用ProgressDialogonPreExecute()onPostExecute()如下面的代碼示例中可用來顯示,而AsyncTask執行進度對話框。我正在使用提供的樣本,但會發生什麼情況是電話開始,它等待網絡交易,然後很快閃爍並隱藏進度對話框。它可以等待整個交易,並且我知道它正在等待doInBackground(),但對話框只是在最後才彈出,使其無效。

在下面的代碼DoEvents()位基本上只是一個非常短暫的睡眠。我試過,沒有它,似乎沒有區別,但它似乎值得嘗試。

class GetFromServerTask extends AsyncTask<String, Void, String> 
    { 
     private Context context; 
     private ProgressDialog dialog; 

     public GetFromServerTask(Context ctx) { 
      context = ctx; 
      dialog = new ProgressDialog(ctx); 
     } 

     @Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
      dialog.setMessage("Loading..."); 
      dialog.show(); 
      DoEvents(); 
     } 

     @Override 
     protected String doInBackground(String... parms) { 
      if(InOfflineMode) 
       return "notdeserializable"; 

      String url = parms[0]; 
      HttpURLConnection urlConnection = null; 
      try { 
       URL typedUrl = new URL(url); 
       urlConnection = (HttpURLConnection) typedUrl.openConnection(); 

       //Add Authorization token 
       if(InDebugMode) { 
        urlConnection.addRequestProperty("AuthToken", AuthToken); 
       } else { 
        urlConnection.addRequestProperty("Authorization", "Bearer " + AuthToken); 
       } 
       urlConnection.addRequestProperty("Accept", "application/json"); 

       DoEvents(); 
       InputStream in = new BufferedInputStream(urlConnection.getInputStream()); 
       byte[] contents = new byte[in.available()]; 

       int bytesRead = 0; 
       String strContents = ""; 
       while((bytesRead = in.read(contents)) != -1){ 
        strContents += new String(contents, 0, bytesRead); 
        DoEvents(); 
       } 

       if(strContents.startsWith("<HTML>")) 
        return "Error: Received unexpected HTML when connecting to service. Make sure you are not connected to a WIFI that requires authentication."; 

       return strContents; 
      } catch(UnknownHostException hex) { 
       return "Error: Could not find server address. Make sure you are connected to the internet. If you just changed connections (ie: turning WIFI on or off) it make take a minute to refresh"; 
      } 
      catch(Exception ex) { 
       String msg = "Error: " + ex.getClass().getName() + ": " + ex.getMessage(); 
       Log.e("TE", msg); 
       return msg; 
      } finally { 
       if(urlConnection != null) 
        urlConnection.disconnect(); 
      } 
     } 

     @Override 
     protected void onPostExecute(String result) { 
      super.onPostExecute(result); 
      if(dialog != null && dialog.isShowing()) 
       dialog.dismiss(); 
      DoEvents(); 
     } 
    } 

我也試過在SO(如下圖所示),建議其他地方略有不同版本完全相同的結果:

protected void onPreExecute() { 
    dialog=ProgressDialog.show(context, "", "Loading...", true, false); 
    super.onPreExecute(); 
} 

我也試着服用ProgressDialogAsyncTask所有的一起並將其顯示在「任務外」,如下所示。在這種情況下,它甚至不會出現。

ProgressDialog dialog = ProgressDialog.show(ServerAccessLayer.m_context, "", "Loading...", true, false); 
String retVal = new GetFromServerTask(ServerAccessLayer.m_context).execute(url).get(); 
dialog.dismiss(); 

return retVal; 
+0

如果您按照此處所述的修復方法進行操作,會發生什麼情況? (http://stackoverflow.com/questions/11943133/android-asynctask-onpreexecute-not-called-indeterminantly) –

+0

@肯狼:相同的行爲。在進度對話框快速彈出然後消失之前,可以看到UI響應(即:從服務器拉取數據的微調器加載)。 – Gakidou

+0

由於執行任務立即返回,您將修補程序顯示爲不在任務之外。這意味着它會立即要求解僱。要做到這一點,你可以在執行前調用show,並在onPostExecute中調用dismiss。 –

回答

3

好的,你的問題是你的.get().get是一個阻塞呼叫。這意味着您不會返回事件循環(Android Framework中代碼爲onCreate,,事件處理程序,onPostExecuteonPreExecute等),直到它返回。如果不返回到事件循環,則不會進入繪圖代碼,也不會顯示進度對話框。如果要顯示對話框,則需要重新構建應用程序以異步實際使用任務。附註 - 如果您在UI線程上調用.get(),那麼您的整個應用程序將凍結並看起來破損。這就是爲什麼他們首先迫使人們不要在UI線程上做網絡IO。

+0

不幸的是,它看起來像這是我必須去的方式。感謝Alejandro,但由於我的架構這個人是正確的,我的應用程序依賴於有數據,並且因爲似乎沒有辦法可靠地阻止讀取,而不會佔用UI線程,這是我必須去的方式。我從來沒有想過我會懷念winsock,但我完全是。 – Gakidou

1

正如@ Gabe-Sechan所說,.get()是您的UI凍結並且您的ProgressDialog不能按需顯示的原因。在另一方面,我不同意他的時候,他說:

如果你想顯示的對話框中,你需要你的應用程序重新架構到 實際使用異步任務。

如果你只是刪除您.get(),讓你在onPreExecute()對話框中顯示,並在解僱onPostExecute(String result),你會得到你在找什麼:在執行任務中所示的ProgressDialog。

UPDATE:

我基於使用Android的的AsyncTask類get()方法的意義/效用開始question

+0

rearchitecture是因爲他的應用程序是爲了假定他總是擁有來自異步任務的數據而編寫的。隨着打電話他有。沒有它,他不會在沒有準備好數據的情況下激活應用程序。這可能(或可能不)需要額外的改變,這取決於他的代碼如何工作。 –

+0

我的意思是說,因爲他希望讓用戶等待AsyncTask完成,那麼只需通過刪除get()並使用ProgressDialog即可實現,而無需額外編碼或重新架構。 –

+0

不基於我讀到他評論的內容。現在他打電話給get,然後他有一堆代碼,然後使用結果。如果他刪除了get,那麼他將不能工作,他必須修復它。 –