0

Given the following flow:

I want the methods to be executed by these threads:

  • OnClick (by system) : ui
  • OnRefresh (1) : ui
  • ReadDb (2) : worker
  • SetData(3) : ui

I could achieve this by making ReadDb async and awaiting it, but it would freeze the UI thread.

Can you think of an approach that doesn't involve implementing Interactors, AsyncTask etc. ?

Thanks.


Edit

I am looking for an elegant solution, please avoid having wrappers like new Handler (Looper.getMainLooper()).post(...), RunOnUiThread in every method of the View etc.

The easiest approach is to use taskt and await:

async OnRefresh() {
    data = await m.ReadDb() 
    v.SetData(data)
}

However, the UI freezes on await m.ReadDb(). I thought that because OnRefresh returns void it would go back and finish executing the parent method (OnClick). Then, once the await is done, it would exeute v.SetData(d). For some reason, it's not the output I am getting.

JonZarate
  • 841
  • 6
  • 28

2 Answers2

0

Something like this:

class View {
    IPresenter p;

    void onClick() {
        p.OnRefresh()
    }

    void setData() {

    }
}

class Presenter implements Listener {
    void OnRefresh() {
        // You can do it with newThread or anything that does async
        async (
            m.readDB()
        )
    }

    void onComplete(Data data) {
        // or you can put it on Model class.
        new Handler(Looper.getMainLooper()).post(() -> {
            // this will be run on ui (or main) thread.
            v.setData(data);
        })
    }
}

class Model {

    Listener lstr;

    void readDB() {
        // read data..

        // completed
        lstr.onComplete(data)
    }
}

interface Listener {
    void onComplete(Data data)
}

You can also add onFailure() and other methods, also RxJava makes this so much simpler take a look at that.

Note: another thing that you need to be worried here is circular references causing by View having a ref to presenter and presenter having a ref to view. you need manually destroy the ref once you no longer need it (onDestroy probably) or memory leak would happen.

Saba
  • 1,208
  • 14
  • 19
  • Thanks Saba, unfortunately, I don't like this approach. I don't want to have `Listeners` for each call I do to the `Model`, nor the `new Handler(Looper.getMainLooper()).post(()` boilerplate code everywhere. I will make that clear in the post for other people too. – JonZarate May 01 '18 at 12:45
0

Actually my approach was correct, but the implementation is not right. I was expecting await m.ReadDb() to be run in a worker thread, but it wasn't. The reason for this, is that I had to explicitly ask for it with Task.Run and await it:

OnRefresh() 
{
    var d = await Task.Run (() => m.ReadDb());
    v.SetData(d)
}

Just writing await doesn't create a new thread, that's why the UI was being blocked.

Check my other question in SO, where it was pointed out to me.

JonZarate
  • 841
  • 6
  • 28