Учитывая следующий поток:
Я хочу, чтобы методы выполнялись этими потоками:
OnClick
(по системе): uiOnRefresh
(1): пользовательский интерфейсReadDb
(2): рабочийSetData
(3): пользовательский интерфейсЯ мог бы добиться этого, сделав ReadDb
асинхронный и Ждитеing его, но это заморозило бы поток пользовательского интерфейса.
Можете ли вы придумать подход, который не предполагает реализации Interactors
, AsyncTask
и т. д.?
Спасибо.
Редактировать
Я ищу элегантное решение, пожалуйста, избегайте использования оберток типа new Handler (Looper.getMainLooper()).post(...)
, RunOnUiThread
в каждом методе View
и т. д.
Самый простой подход - использовать taskt
и await
:
async OnRefresh() {
data = await m.ReadDb()
v.SetData(data)
}
Однако пользовательский интерфейс на await m.ReadDb()
зависает. Я думал, что, поскольку OnRefresh
возвращает void
, он вернется и завершит выполнение родительского метода (OnClick
). Затем, как только await
будет готов, он запустит v.SetData(d)
. По какой-то причине я получаю не такой результат.
@SabaJafarzadeh Что вы имеете в виду под send it to MainThread
?
означает запускать его в потоке пользовательского интерфейса. (автор Handler(Looper.gerMainLooper()
)
Что-то вроде этого:
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)
}
Вы также можете добавить onFailure () и другие методы, также RxJava делает это намного проще, взгляните на это.
Примечание: еще одна вещь, о которой вам нужно беспокоиться, - это циклические ссылки, вызванные тем, что View имеет ссылку на ведущего, а ведущий имеет ссылку для просмотра. вам нужно вручную уничтожить ссылку, если она вам больше не нужна (возможно, onDestroy), иначе произойдет утечка памяти.
Спасибо, Саба, к сожалению, мне такой подход не нравится. Я не хочу иметь Listeners
для каждого звонка, который я делаю к Model
, и не хочу везде использовать шаблонный код new Handler(Looper.getMainLooper()).post(()
. Я объясню это в посте и для других людей.
На самом деле мой подход был правильным, но реализация неправильная. Я ожидал, что await m.ReadDb()
будет запущен в рабочем потоке, но этого не произошло. Причина этого в том, что мне пришлось явно запросить это с Task.Run
и await
:
OnRefresh()
{
var d = await Task.Run (() => m.ReadDb());
v.SetData(d)
}
Простая запись await
не создает новый поток, поэтому пользовательский интерфейс был заблокирован.
Проверьте мой другой вопрос в SO, где мне на это указали.
Зачем его ждать? вы можете выполнить
ReadDb
async, и как только данные будут загружены, отправьте их в MainThread и выполните v.setData ...