2012-10-28 91 views
4

我很困惑我的應用程序的設計。我需要不斷輪詢服務器以從中獲取新數據。我很困惑以固定的時間間隔運行Async Task還是Service running是後臺更好的選擇。該線程將僅在應用程序運行時運行服務v/s AsyncTask

回答

2

Android Service不在後臺線程中。

因此,您應該運行一個服務,每次您要輪詢時都會啓動一個ASyncTask。

請注意,與其他應用程序對象一樣,服務在其宿主進程的主線程中運行。這意味着,如果你的服務要做任何CPU密集型(如MP3播放)或阻塞(如網絡)操作,它應該產生自己的線程來完成這項工作。有關這方面的更多信息可以在「進程和線程」中找到。 IntentService類可作爲Service的標準實現提供,它具有自己的線程,用於調度要完成的工作。

1

Service不應與AsyncTask相比較。我想你在這裏最有可能的意思是IntentService - 儘管有通用名稱,但這與Service稍有不同。

至於定期抓取,我會堅持使用反覆報警(使用AlarmManager)和(最可能)使用IntentService來抓取。

這裏你AsyncTask fundamentals和一些tutorials 了這裏你IntentService fundamentalstutorials

注意得到,那IntentService作業設計排隊,而AsyncTasks可以運行完全相同常。但請注意regression related to AsyncTask handling in newer APIs。解決方案只是更多的代碼行,這不是什麼大問題,但值得一提的是。

編輯

有許多關於生命週期的AsyncTask是債券到活動的生命週期中的誤解浮動。這是錯誤。 AsyncTask獨立於Activity。 Finishing Activity對任何AsyncTasks都沒有做任何事情,除非你用代碼從onDestroy()清理它們。然而,如果一個活動的進程在後臺被殺害,那麼AsyncTask也將被殺死,因爲整個進程中的一部分被殺死。

+0

IntentService不是更多的隊列類型體系結構嗎? – Ankuj

+0

是的,但我認爲它不是定期抓取的問題,除非抓取可以重疊。我個人主要使用'AsyncTask',但這一切都取決於應用程序體系結構。 –

+0

另外我還有一個疑問。像異步任務與UI線程鏈接。但是這個輪詢將獨立於UI開始,並且不需要給用戶任何通知,所以我想這可能排除其中一個缺點 – Ankuj

1

如果你想「連續輪詢」,一個asyncTask贏得'不要做。當您的應用被Android停止時,任務停止。正如Blundell已經指出的那樣,服務本身也不會這樣做。服務在主線程中運行,並且您不希望在主線程中進行輪詢。有兩種方法:創建一個Service,它自己創建一個線程來完成您想要的任務,或者讓它調度在AsyncTask或獨立線程中執行的輪詢。我儘量不在我的應用程序中進行輪詢,但如果必須,請在您的服務中創建一個特殊線程,以便進行輪詢,這對我來說似乎是最好的。

根據您的應用程序的功能和輪詢的內容,您可以爲單獨的線程指定較低的優先級,這樣就不會妨礙其他處理。

+0

**這就是城市傳奇** AsyncTask **與**無關。Finishing Activity對任何AsyncTasks都沒有做任何事情,除非你用代碼從onDestroy()清理它們。然而,如果一個活動的**進程**在後臺被殺害,那麼AsyncTask也會被殺死,因爲整個進程的一部分被殺死。 –

+1

那你有什麼意見? AsyncTask不會確保應用程序保持輪詢,因爲當Android需要空間時,它會銷燬應用程序並停止輪詢。在一項服務中,投票繼續進行。我說「活動停止」而不是「應用程序停止」這一事實,這是您給我的答案投下的理由嗎?可憐...... – Christine

+0

你在散佈虛假信息。起初,這是我的觀點。其次,正如我的回答所述,AsyncTask不適用於定期任務。最後,如果你不能接受批評,也許你不應該首先參加對話。 –

0

線程運行,只有當應用程序正在運行

然後AsyncTask將是最簡單的解決方案。使用後臺線程中的publishProgress()定期將數據發送到應用程序線程。使用Thread.sleep()doInBackground()中設置所需的時間間隔。此外,請確保您在onResume()活動方法中啓動任務,並在活動的onPause()方法中結束此任務。

例子:

public class MyActivity extends Activity { 
    private AsyncTask<Void,String,Void> mAsyncTask; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     mAsyncTask = new MyTask(); 
     mAsyncTask.execute(); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     if(mAsyncTask != null){ 
      mAsyncTask.cancel(true); 
     } 
    } 

    private void onServerResponse(String response){ 
     Toast.makeText(this, "Got response !", Toast.LENGTH_SHORT).show(); 
    } 

    private final class MyTask extends AsyncTask<Void,String,Void>{ 

     @Override 
     protected Void doInBackground(Void... voids) { 
      while (!isCancelled()){ 

       String response = ""; 

       //server query code here 

       publishProgress(response); 
       Log.i("TEST", "Response received"); 

       //sleep for 5 sec, exit if interrupted ,likely due to cancel(true) called 
       try{ 
        Thread.sleep(5000); 
       }catch (InterruptedException e){ 
        return null; 
       } 
      } 

      return null; 
     } 

     @Override 
     protected void onProgressUpdate(String... values) { 
      super.onProgressUpdate(values); 
      if(values.length > 0){ 
       onServerResponse(values[0]); 
      } 
     } 
    } 
} 
5

你已經有些答覆你的問題,但我認爲這一點,實在值得總結...

你需要什麼

當你想運行需要一些時間才能完成的代碼應始終在UI線程的單獨線程中運行。

可以實現在2種方式:

使用Thread

這是最簡單的一種,如果不從,新線程UI線程需要大量的溝通。如果你需要溝通,你可能不得不使用Handler來做到這一點。

使用AsyncTask

在一個單獨的線程也可以運行,並已經實現了與UI線程一些溝通渠道。因此,如果您需要將此通信返回到用戶界面,則最好使用此方法。

你不需要什麼

Service

這主要是用來保留一些代碼,你退出主應用程序即使在運行,除非你生成一個新的,將在UI線程中運行線程使用上述選項。你說你的線程是在你退出應用程序時被終止的,所以這不是你所需要的。

IntentService

這可以通過可以就一塊由你定義的代碼,即使應用程序未運行時的外部事件(即BroadcastReceiver)被激活。再次根據您的要求,這不是您正在尋找的。

問候。

+0

而不是一個線程,您可以使用一個執行程序。如果您希望輪詢在Android將應用從堆棧中移除時繼續進行,那麼您確實需要一項服務。你不希望它繼續下去,那麼服務是你不需要的開銷。 – Christine

+0

我不同意第3點關於服務。你說「你說你的線程是在你退出應用程序時被終止的,所以這不是你需要的。」,這是正確的。但是配置更改呢?屏幕方向改變和用戶攔截呼叫? - 否則寫得很好! –