4

メソッド runReport() から結果を返す、AsyncTask から呼び出される一連のインスタンスのクラスを作成しました。ワーカー スレッドは正常に作成されますが、何らかの理由で Callable の call() メソッドが実行されません。私は何を間違っていますか?

//Problem: doStuff() never gets called, even though the worker thread gets created.

@Override
public ReportResult runReport() throws InterruptedException, ExecutionException {
    Callable<ReportResult> report = new Callable<ReportResult>() {

        @Override
        public ReportResult call() throws Exception {
            doStuff();
            ...
            return new ReportResult(varWrittenByMethod);
        }
    };
    FutureTask<ReportResult> result = new FutureTask<ReportResult>(report);

    //I tried a few of these ExecutorService factory methods, with the same result.
    //I only made my own ThreadFactory to verify the worker was created
    ExecutorService es = Executors.newSingleThreadExecutor(new ThreadFact());
    es.submit(report);

    ReportResult finalResult = result.get();
    es.shutdownNow();
    return finalResult;
}


private class ThreadFact implements ThreadFactory{

    @Override
    public Thread newThread(Runnable r) {
        Log.d(TAG, "Created worker Thread");
        return new Thread(r);
    }

}

私が知る限り、これは独自の Thread で FutureTask として実行する必要があります。これは、次のことを行う必要があるためです (戻り値以外はすべて doStuff() 内にあります)。

  • いくつかの同期セットアップを実行します (AsyncTask はそれを UI スレッドから切り離します)。
  • Looper.prepare() を呼び出す
  • リスナーを登録する
  • Looper.loop() を呼び出し、一定期間にわたってリスナーからいくつかのコールバックをキャッチします。
  • 十分なデータポイントがある場合、リスナーのコールバック内で Looper.myLooper().quit() を呼び出します
  • 結果を返す

私はこれを行うためのより良い方法を受け入れています。最初は AsyncTask にこの呼び出しを行わせてから、そのスレッドで Looper.loop() を実行しましたが、結果を返す前にリスナーから Looper.myLooper.quit() を呼び出す必要があったため、これらのオブジェクトのキューを処理できませんでした。 、スレッドのメッセージ キューを不可逆的に汚染しました。

4

2 に答える 2

4

スレッド ファクトリは、渡された Runnable を作成されたスレッドに伝達しません。ThreadFactory で、次のことを試してください。

return new Thread(r);

また、明示的に作成したものではなく、submit メソッドによって返された FutureTask を使用する必要があります。例えば

FutureTask<ReportResult> result = es.submit(report);
ReportResult finalResult = result.get();
于 2012-12-13T01:53:14.750 に答える
2

注意として、AsyncTask のスレッドはアクティビティのライフサイクルの変更中に強制終了されるため、AsyncTask からこのレベルの作業を行ったことを後悔する可能性があります。IntentService で非同期セットアップを行うことをお勧めします。Looper() が必要ない場合は、HandlerThreads ではなくプレーン スレッドを使用できます。

于 2012-12-13T02:07:44.440 に答える