0

2 つの非同期タスクを実装しようとしています。一方は他方が完了するのを待つ必要があります。

次のようなテストケースを作成します。

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!

そのため、一方が他方の実行を妨げていると思います。彼らはdoInBackground実際に同じスレッドで計算し、LOCK.wait()このスレッドがそれ以上実行されないようにブロックしましたか?

それを修正する (そして Android 2.2 との互換性を維持する) 方法はありますか?

WaitingOnLoaderTask注:2番目の時間は基本的に私が望むものですが、他のタスクの実装では、他のタスクが終了したときにのみ実行されることを保証できません。

4

2 に答える 2

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が完了するまで待機します。

于 2013-03-08T17:55:22.873 に答える
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();
}

static注:構成の変更 (ローテーションなど) でアクティビティがリークしないように、AsyncTasks をマークする必要があります。

于 2013-03-08T18:02:08.873 に答える