Синхронное выполнение длительно выполняющихся методов в сервисе

#java #android #multithreading #android-service #worker-thread

#java #Android #многопоточность #android-сервис #рабочий поток

Вопрос:

У меня есть служба Android, которая имеет набор операций :

MyService.java

 public class MyService extends Service {

    public int login() {
      //Invokes yet another logic to initiate login and waits for result 
      //synchronously and returns status code based on result of operation
    }

    public int logout() {
      //Invokes yet another logic to initiate logout and waits for result 
      //synchronously and returns the status code
    }
}
  

Я вызываю методы, скажем, из клиентской активности, MyClientActivity.java находящиеся в том же процессе.

Для каждой операции сервис вызывает некоторую логику и синхронно ожидает результата. Когда сервис выполняет всю эту логику, я не хочу, чтобы пользователь выполнял что-либо еще и просто показывал экран загрузки. Итак, в принципе, после того, как я инициировал операцию, я хочу MyClientActivity синхронно ожидать код состояния. Теперь я знаю, что не могу заблокировать поток пользовательского интерфейса, чтобы избежать ANR.
Как я могу выполнить эту операцию в отдельном потоке, а затем получить результат обратно, чтобы я мог соответствующим образом распространить результат обратно пользователю, изменив пользовательский интерфейс на основе этого результата.

Я довольно новичок в этом и не могу по-настоящему понять концепции. Если кто-нибудь может объяснить вместе с примером, который был бы полезен.

Комментарии:

1. используйте библиотеку обратных вызовов / локальных трансляций / EventBus. Итак, в activity вы просите сервис выполнить запрос, а затем блокируете пользовательский интерфейс (с представлением загрузки). Затем сервис выполняет операции асинхронно, и когда операция завершается — он вызывает некоторый метод Activity (обратный вызов), отправляет локальную широковещательную рассылку, которую вы получаете в Activity, или отправляет событие, которое вы получаете в Activity (библиотека EventBus). Затем в Activity вы разблокируете пользовательский интерфейс и обрабатываете результат

2. Я думал о том, чтобы сделать что-то подобное. Я регистрирую экземпляр обратного вызова из MyClientActivity самого себя с помощью MyService , и служба может вызвать метод success / failure при этом обратном вызове. MyClientActivity будет иметь логику для управления пользовательским интерфейсом в соответствующих методах успеха / неудачи реализации обратного вызова. Я сомневаюсь, зачем мне добавлять все это усложнение и дополнительный код, когда мне точно не нужно асинхронное поведение. Я хотел решение без обратных вызовов. В принципе MyClientActivity следует ожидать результата, но в рабочем потоке вместо основного потока пользовательского интерфейса, чтобы избежать ANR.

3. ожидание результата в другом потоке намного сложнее, чем использование обратных вызовов, а также вам в любом случае придется передать что-то, чтобы уведомить поток о завершении операции.

4. Есть ли у вас какая-либо ссылка на пример реализации, в которой клиент ожидает результата в рабочем потоке, а затем уведомляет основной поток? Я просто хочу проанализировать обе модели реализации на предмет гибкости добавления дополнительных операций, если это потребуется в будущем. Я хочу посмотреть, насколько хорошо обе модели поддерживают потенциальные операции с различными требованиями. Также я хочу проанализировать, насколько легко я могу справиться с крайними случаями в обеих моделях, такими как сбой вновь созданного процесса (порожденного MyService ), где MyService , возможно, никогда не удастся вызвать обратный вызов и т.д.

5. Мне особенно нужны были ссылки на реализации с манипулированием потоками, потому что это новая концепция для меня. Исходя из этого, я хочу выбрать подход.

Ответ №1:

В Android существует множество способов выполнять асинхронную работу, как вы описали. Вы можете использовать сервис, загрузчик, если вы используете модифицированную библиотеку для сетевых запросов, в которую встроены асинхронные запросы, поэтому следуйте документации. Также существует RxJava, но его кривая обучения довольно крутая.

Ответ №2:

Я добился этого, используя a HandlerThread для создания a, Handler в который я отправляю Runnables для выполнения фоновых задач.
Для выполнения этих задач основного потока (задач пользовательского интерфейса) Я использую mainLooper для создания другого, Handler в который я отправляю сообщения Runnables для выполнения операций с представлениями.
Приблизительное представление кода :

 mBackgroundHandler.post(new Runnable() {

    @Override
    public void run() {
        //Do background operation in synchronous manner as usual.

    mMainHandler.post(new Runnable() {
        @Override
        public void run() {
            //Remove loader, update UI
        }
    });
  }
});