0

I saw many questions about getting results from async task, but none of them solved my problem. The thing I want to do is get from async task array of MyClass objects and use them in UI, but in different situations I have different UI. Sometimes I fill recyclerview with my array, sometimes I fill endless tabbed activity with my array. This means that I cant pass my UI element to Async task in order to handle it in onPostExecute(). The result I want to get from Async task is exactly array of MyClass objects and then in different situations work with it in different ways. And also one important thing is that I should fill my UI only after AsyncTask executes (because if it's still executing I have no data to fill UI with), so I can't simply write something like

MyClass[] result = new MyAsyncTask().execute().getResult()
MyUI.fillWith(result)

because most likely I will get NPE.

So how can I get my result back as array of MyClass objects and fill my UI with it only after I get the result (So in UI thread I should get info that my asynctask did all the work and only after that I can fill UI with my data. And of course I dont want to block my UI thread)?

Handling UI in onPostExecute() won't solve my problem because of reasons I wrote earlier. Covering AsyncTask with interface also doesnt seem like something I need. And I saw solution with unique token for AsyncTask but I didnt get how that works.

Murat Karagöz
  • 35,401
  • 16
  • 78
  • 107
Leopik
  • 303
  • 2
  • 14
  • But you have to handle the UI thread in onPostExecute because that's just how it works. Maybe you shouldn't use AsyncTask, though. Have you considered other networking libraries? – OneCricketeer Nov 04 '16 at 13:44
  • 1
    That top answer is essentially what you are after, just replace `String output` in the response interface with `MyClass[] output`, and you should be set – OneCricketeer Nov 04 '16 at 13:47
  • @cricket_007 Yes that is what I needed, thanks. But this seems like complicated solution. That is strange, because as I understand this is a common problem. – Leopik Nov 04 '16 at 13:54
  • 1
    It's not complicated and the answer from Joseph solves it. – Murat Karagöz Nov 04 '16 at 13:55
  • 1
    It's complex, but not complicated. Volley, OkHttp, Retrofit, RxJava, etc asynchronous library all do the exact same thing with interface callbacks. – OneCricketeer Nov 04 '16 at 13:56

1 Answers1

3

Rather than passing your UI element directly to the AsyncTask, create an interface representing the action to take once the task is complete:

public interface MyTaskHandler {
  void onComplete(MyClass[] results);
}

And make your task accept this interface and call it in onPostExecute:

public class MyTask extends AsyncTask<..., ..., MyClass> {
  private MyTaskHandler myTaskHandler;

  public MyTask(MyTaskHandler myTaskHandler) { 
    this.myTaskHandler = myTaskHandler;
  }

  @Override
  public void onPostExecute(MyClass[] results) {
    myTaskHandler.onComplete(results);
  }
}

(in the real implementation you will need to use WeakReferences or null out the reference when your activity is destroyed, just as you would do with views since your handler will generate have a reference to some view)

Then you can pass different implementations of MyTaskHandler based on what you want to do:

public class MyActivity extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    new MyAsyncTask(new MyTaskHandler() {
      @Override
      public void onComplete(MyClass[] results) {
        // load into list view
      }
    }).execute();

    new MyAsyncTask(new MyTaskHandler() {
      @Override
      public void onComplete(MyClass[] results) {
        // load into tabs
      }
    }).execute();
  }
}
Joseph Earl
  • 23,351
  • 11
  • 76
  • 89