Question

I've written a class, a series of instances of which are intended to be called from an AsyncTask, which will return a result from the method runReport(). It creates a worker thread just fine, but for some reason it then doesn't execute the Callable's call() method. What am I doing wrong?

//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);
    }

}

As far as I can tell, I have to do this as a FutureTask in its own Thread, because it needs to do the following (all of which apart from the return is inside doStuff() ):

  • Do heavy some synchronous setup (The AsyncTask keeps that off the UI thread)
  • Call Looper.prepare()
  • Register a listener
  • Call Looper.loop(), catch a few callbacks from the listener over a period of time.
  • Call Looper.myLooper().quit() inside the listener callback when I have enough datapoints
  • Return the result

I'm open to better ways to do this. I originally let the AsyncTask make this call, then ran Looper.loop() on its thread, but I couldn't process a queue of these objects since I needed to call Looper.myLooper.quit() from the listener before returning a result, which poisoned the thread's message queue irreversibly.

Was it helpful?

Solution

Your thread factory doesn't propagate the passed Runnable to the created thread. In your ThreadFactory, try:

return new Thread(r);

Also, you should be using the FutureTask returned by the submit method, not the one you created explicitly. E.g.

FutureTask<ReportResult> result = es.submit(report);
ReportResult finalResult = result.get();

OTHER TIPS

As a note, you probably will regret doing this level of work from an AsyncTask, because the threads in an AsyncTask will get killed during an Activity lifecycle change. Better to do the asynchronous setup in an IntentService. If you don't need Looper(), you can use plain threads rather than HandlerThreads.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top