2013-03-08 84 views
0

我試圖實現2個異步任務,其中一個應該等待另一個完成。AsyncTask如何在沒有deadLock的情況下等待另一個

我做一個測試案例吧,看起來像這樣:

public class MainActivity extends Activity{ 

    public static boolean SYNCING = false; 
    public static Object LOCK = new Object(); 

    public static void setSync(){ 
     Log.i(TAG, "setting Sync=true"); 
     synchronized (LOCK) { 
      SYNCING = true; 
     } 
    } 

    public static void waitForSync(){ 
     Log.i(TAG, "waiting for Sync"); 
     synchronized (LOCK) { 
      try{ 
       while (SYNCING){ 
        LOCK.wait(); 
       } 
      } catch (InterruptedException ignore){} 
     } 
    } 

    public static void setSyncFinish(){ 
     Log.i(TAG, "setSyncFinish to notify all"); 
     synchronized (LOCK) { 
      SYNCING = false; 
      LOCK.notifyAll(); 
     } 
    } 

    public class WaitingOnLoaderTask extends AsyncTask<Void, Void, Void>{ 

     @Override 
     protected Void doInBackground(Void... params) { 
      Log.i(TAG, "doInBackground of WaitingForLoaderTask"); 

      try { 
       Thread.sleep(500); 
      } catch (InterruptedException e) { 

      } 

      waitForSync(); 
      Log.i(TAG, "finishedWaiting!"); 
      return null; 
     } 

    } 

    public class LoaderTask extends AsyncTask<Void, Void, Void>{ 

     long mRuntime; 
     int mTimes; 

     public LoaderTask(long runtime, int times){ 
      mRuntime = runtime; 
      mTimes = times; 
     } 

     @Override 
     protected Void doInBackground(Void... params) { 
      while(mTimes >= 0){ 
       Log.i(TAG, "sleeping for " + mTimes + " times for " + mRuntime + " milliseconds"); 
       mTimes--; 
       try { 
        Thread.sleep(mRuntime); 
       } catch (InterruptedException e) { 
        Log.e("MainActivity", "Interrupted", e); 
       } 
      } 

      setSyncFinish(); 

      return null; 
     } 

    } 
} 

但我不能讓WaitingOnLoaderTask正確地等待。如果我的onCreate運行此

new WaitingOnLoaderTask().execute((Void[])null); 
new LoaderTask(1000, 5).execute((Void[])null); 

我得到這樣一個logOutput(死鎖發生):

03-08 18:17:23.309: I/myUniqueLogTag(4432): setting Sync=true 
03-08 18:17:23.317: I/myUniqueLogTag(4432): doInBackground of WaitingForLoaderTask 
03-08 18:17:23.817: I/myUniqueLogTag(4432): waiting for Sync 

new LoaderTask(1000, 5).execute((Void[])null); 
new WaitingOnLoaderTask().execute((Void[])null); 

我得到一個日誌是這樣的:

03-08 18:18:53.082: I/myUniqueLogTag(4621): sleeping for 5 times for 1000 milliseconds 
03-08 18:18:54.082: I/myUniqueLogTag(4621): sleeping for 4 times for 1000 milliseconds 
03-08 18:18:55.090: I/myUniqueLogTag(4621): sleeping for 3 times for 1000 milliseconds 
03-08 18:18:56.082: I/myUniqueLogTag(4621): sleeping for 2 times for 1000 milliseconds 
03-08 18:18:57.090: I/myUniqueLogTag(4621): sleeping for 1 times for 1000 milliseconds 
03-08 18:18:58.106: I/myUniqueLogTag(4621): sleeping for 0 times for 1000 milliseconds 
03-08 18:18:59.113: I/myUniqueLogTag(4621): doInBackground of WaitingForLoaderTask 
03-08 18:18:59.113: I/myUniqueLogTag(4621): setSyncFinish to notify all 
03-08 18:18:59.621: I/myUniqueLogTag(4621): waiting for Sync 
03-08 18:18:59.621: I/myUniqueLogTag(4621): finishedWaiting! 

所以我想一個是防止o運行。他們是否實際上在同一個線程中計算了它們的doInBackground,並且LOCK.wait()阻止此線程進一步執行?

有沒有辦法解決它(並保持與Android 2.2兼容)?

注意: 第二次基本上是我想要的,但在其他任務實現中,我不能確定WaitingOnLoaderTask僅在另一個完成時纔會執行。

+2

「我試圖實現2個異步任務,其中一個人應該等待另一個完成」 - 爲什麼它不只是一個'AsyncTask'呢? – CommonsWare 2013-03-08 17:28:39

+0

如果你想保持任務分開,或者從另一個的'onPostExecute()'調用。 – Geobits 2013-03-08 17:29:23

+0

不可能。在「真實世界的使用」中,第一個任務是將事情與服務器同步並將結果存儲在數據庫中。它從'Application'調用。另一個從db接收這些數據,但必須等待,直到第一個完成同步,並且可以在同步完成之前被調用。在'onPostExecute'中開始第二個是沒有意義的,因爲結果將無處可用。 – 2013-03-08 17:33:54

回答

1

最好的辦法是使用Geobits建議。

可以使用onPostExecute()函數來調用下一個異步任務,因此將執行它:

class WaitingOnLoaderTask extends AsyncTask<Void,Void,Void> 
{ 
    protected void onPreExecute(Void) 
    { 
     super.onPreExecute(); 
    } 

    protected void doInBackground(Void... params) 
    { 
     //Commands for first AsyncTask 
    } 

    protected void onPostExecute(Void) 
    { 
     //Call AsyncTask 2 
    } 
} 

這樣,它會等到任務1完成。

+0

,正如我已經告訴過2次那樣:這是不可能的,因爲第二個是從APP內部調用的,其中第一個是在'Application '! – 2013-03-08 17:59:22

+0

@RafaelT:ok然後第一個任務執行爲'new LoaderTask(1000,5).execute((void [])null).get();'現在秒等待,直到第一個未完成 – 2013-03-08 18:06:27

+0

'AsyncTask.get'將會阻塞'MainThread'將導致'ANR' – 2013-03-08 18:43:58

1

您的代碼在Android 3.2及更低版本上按預期工作。在更高版本的Android版本AsyncTasks不執行並行嘗試這讓它在Android 4+工作:

LoaderTask loaderTask = new LoaderTask(1000, 5); 
WaitingOnLoaderTask waitingTask = new WaitingOnLoaderTask(); 
if (Build.VERSION.SDK_INT >= 14) { 
    loaderTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
    waitingTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
} else { 
    loaderTask.execute(); 
    waitingTask.execute(); 
} 

注意:您應該標記您AsyncTasks爲static,以避免對配置更改(例如旋轉)漏水活動。

相關問題