解決策は次のようになります。
AsyncTask
互いに干渉する可能性のあるsを生成するすべてのクラスは、次のExecutor
ように独自のクラスを取得します(スレッドプールなどを使用して、好きなように複雑にします)。
private Executor serviceExecutor = new Executor() {
public void execute(Runnable command) {
new Thread(command).start();
}
};
VinceFRが指摘しているように、次のように呼び出すことAsyncTask
で、与えられたものに対してを実行できます(タスクに定期的に渡すパラメーターはどこにありますか)。Executor
payload
task.executeOnExecutor(serviceExecutor, payload);
ただし、これは下位互換性を損ないます-ジンジャーブレッド以前との互換性。また、Honeycombをサポートする場合は、この呼び出しがUIスレッドで発生することを確認する必要があります。JellyBeanがこれを自動的に処理します。
ここで注意が必要なのは、サービスを独自のスレッドで実行し続けることです。Androidの多くのことは、これが必要以上に難しいように思われます(または、ここでいくつかの情報が不足している可能性があります)。を使用することはできません。これは、が最初に引き継いだIntentService
ときに自動的にシャットダウンし、コールバックを完了させます。AsyncTask
onHandleIntent
サービスで独自のスレッドとイベントループを設定する必要があります。
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
。