2

私の理解では、使用するのは非常に便利ですが、AsyncTask2つの重要な制限があります。

  1. doInBackgroundいずれのインスタンスも同じワーカースレッドを共有します。つまり、1つの長時間実行するとAsyncTasks、他のすべてのスレッドがブロックされる可能性があります。

  2. executeonPostExecuteおよびその他の「同期」メソッドは、常にUIスレッドで実行する必要があります。つまり、タスクを開始するスレッドでは実行しないでください。

IntentServiceアプリのクライアントサーバー通信を担当する既存のAsyncTasksをバックグラウンドで再利用しようとしたときに、問題が発生しました。サービスのタスクは、ワーカースレッドでUIアクティビティのタスクと時間の経過とともに競合します。また、サービスはUIスレッドにフォールバックするように強制されますが、そのサービスはバックグラウンドで静かに作業を実行する必要があります。

これらの制限を取り除く/回避するにはどうすればよいですか?私は基本的に達成したい:

  1. AsyncTaskによく似たフレームワーク(多くの重要なコードをそこに移行する必要があるため)。

  2. このようなタスクの各インスタンスはdoInBackground、すべてのインスタンスに対して単一のワーカースレッドではなく、独自のスレッドで実行する必要があります。

    編集:これを指摘するためのThxからVinceFRは、executeOnExecutorの代わりに呼び出すだけで実現できますexecute

  3. のようなコールバックonPostExecuteは、を呼び出してタスクを開始したのと同じスレッドで呼び出すexecute必要があります。これは、UIスレッドである必要はありません。

私は、私がこのようなものを要求する最初の人ではないと思います。したがって、私は疑問に思います:これを達成するために推奨できるサードパーティのライブラリはすでにありますか?そうでない場合、これを実装する方法は何でしょうか?

前もって感謝します!

4

1 に答える 1

0

解決策は次のようになります。

AsyncTask互いに干渉する可能性のあるsを生成するすべてのクラスは、次のExecutorように独自のクラスを取得します(スレッドプールなどを使用して、好きなように複雑にします)。

private Executor serviceExecutor = new Executor() {
    public void execute(Runnable command) {
        new Thread(command).start();
    }
};

VinceFRが指摘しているように、次のように呼び出すことAsyncTaskで、与えられたものに対してを実行できます(タスクに定期的に渡すパラメーターはどこにありますか)。Executorpayload

task.executeOnExecutor(serviceExecutor, payload);

ただし、これは下位互換性を損ないます-ジンジャーブレッド以前との互換性。また、Honeycombをサポートする場合は、この呼び出しがUIスレッドで発生することを確認する必要があります。JellyBeanがこれを自動的に処理します。

ここで注意が必要なのは、サービスを独自のスレッドで実行し続けることです。Androidの多くのことは、これが必要以上に難しいように思われます(または、ここでいくつかの情報が不足している可能性があります)。を使用することはできません。これは、が最初に引き継いだIntentServiceときに自動的にシャットダウンし、コールバックを完了させます。AsyncTaskonHandleIntent

サービスで独自のスレッドとイベントループを設定する必要があります。

public class AsyncService extends Service {

private static final String TAG = AsyncService.class.getSimpleName();
private class LooperThread extends Thread {
    public Handler threadHandler = null;

    public void run() {
        Looper.prepare();
        this.threadHandler = new Handler();
        Looper.loop();
    }
}
private LooperThread serviceThread = null;
private Handler serviceThreadHandler = null;

@Override
// This happens on the UI thread
public void onCreate() {
    super.onCreate();
}

@Override
// This happens on the UI thread
public int onStartCommand(Intent intent, int flags, int startId) {
    this.serviceThread = new LooperThread();
    this.serviceThread.start();
    while(this.serviceThread.threadHandler == null) {
        Log.d(TAG, "Waiting for service thread to start...");
    }
    this.serviceThreadHandler = this.serviceThread.threadHandler;
    this.serviceThreadHandler.post(new Runnable() {
        @Override
        public void run() {
            doTheFirstThingOnTheServiceThread();
        }
    });
    return Service.START_STICKY;
}

// doTheFirstThingOnTheServiceThread

}

AsyncTaskいいえ、UIスレッドに戻るたびに、代わりにサービススレッドに到達することを確認する必要はありません。

// This happens on the serviceThread
private void doTheFirstThingOnTheServiceThread() {
    // do some stuff

    // here we can reuse a class that performs some work on an AsyncTask
    ExistingClassWithAsyncOperation someUsefullObject = new ExistingClassWithAsyncOperation();
    // the existing class performs some work on an AsyncTask and reports back via an observer interface
    someUsefullObject.setOnOperationCompleteListener(new OnOperationCompleteListener() {
        @Override
        // This happens on the UI thread (due to an ``AsyncTask`` in someUsefullObject ending)
        public void onOperationComplete() {
            serviceThreadHandler.post(new Runnable() {
                @Override
                public void run() {
                    doTheSecondThingOnTheServiceThread();
                }
            });
        }
    }
    someUsefulObject.performOperation();
}

// This happens on the serviceThread
private void doTheSecondThingOnTheServiceThread() {
    // continue working on the serviceThread
}

だから、これは私のために働きます。このためのより簡単な解決策を見て喜んでいます。ExistingClassWithAsyncOperationこのソリューションでは、UIスレッドでがコールバックされることをサービスが認識している必要があることに注意してください。私はこの依存関係が特に好きではありませんが、今のところもっとうまくやる方法がわかりません。ただし、を使用して非同期操作を実行する既存のクラスの多くを書き直す必要はありませんAsyncTask

于 2013-03-19T08:32:25.497 に答える