#java #android #multithreading #android-asynctask #android-service
#java #Android #многопоточность #android-asynctask #android-сервис
Вопрос:
У меня есть длительное вычисление, которое принимает данные датчика в качестве аргументов.
После получения результата вычисления я хотел бы вызвать метод для обновления представления.
Это вычисление может занять некоторое время, поэтому я не могу запустить его внутри кода Activity при получении данных датчика, потому что поток пользовательского интерфейса зависает или замедляется.
Поскольку я хочу запускать это вычисление каждый раз, когда получаю новые данные датчика, какие варианты предлагает мне Android?
Я пробовал использовать AsyncTask. Я бы запустил AsyncTask для выполнения вычисления с новыми данными датчика, и внутри него был бы вызван метод обновления представления onPostExecute
.
К сожалению, такой подход создавал проблемы с синхронизацией анимации: AsyncTask мог завершиться после следующего, и обновление представления вызывалось с устаревшей информацией, что фактически приводило к сбоям в анимации.
Я также пытался запустить ту же AsyncTask с executeOnExecutor
, передав ей исполнителя с одним потоком, но это не остановило дрожание анимации.
Наконец, я попытался запустить IntentService с обратным вызовом ResultReceiver внутри MainActivity. Хотя я могу запустить ее, она запускается только один раз. Я неправильно понял, для чего предназначены IntentServices? Кажется, я не могу запустить ее несколько раз (используя метод, который создает intent с дополнительными параметрами и вызывает startService
с ним).
Резюме: У меня есть медленный метод, который работает с данными датчика. Я хочу запускать ее в фоновом режиме каждый раз, когда получаю новые данные датчика, и использовать ее результат / ответ для обновления представления.
Есть предложения?
Комментарии:
1. используйте Rx java, это работает так же, как асинхронная задача, и работает намного лучше
Ответ №1:
Ваш сервис здесь…..
public class One extends Service {
public static final long NOTIFY_INTERVAL = 10 * 1000;
private Handler handler = new Handler();
private Timer timer = null;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate()
{
if (timer != null)
{
timer.cancel();
} else
{
timer = new Timer();
}
timer.scheduleAtFixedRate(new DisplayTime(), 0, NOTIFY_INTERVAL);
}
class DisplayTime extends TimerTask
{
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
recall();
Toast.makeText(getApplicationContext(), "run", Toast.LENGTH_SHORT).show();
}
});
}
public void recall() {
// Write here Async Task Method......
}
}
@Override
public void onDestroy()
{
super.onDestroy();
Toast.makeText(getApplicationContext(), "des", Toast.LENGTH_SHORT).show();
}
}
Комментарии:
1. Как моя активность будет взаимодействовать с этой службой? Скажем, если моя активность получает обновления данных датчика, как она может отправить их в эту службу и получить от нее ответ?
2. Привет @volcano-secret, мне удалось связаться с Activity с помощью ResultReceiver. В конечном итоге я не совсем использовал ваш подход (мне не нужна была временная задача), но подкласс Service и использование HandlerThread сработали для меня.
Ответ №2:
Хотя я не уверен, какую анимацию вы используете, в зависимости от структуры вашего приложения и кода, несколько вариантов могут заключаться в том, что вместо обновления данных в onPostExecute (), посмотрите, можете ли вы сделать это в методе обратного вызова анимации, который сообщает вам, что анимация завершена, т. Е. Вычислите ее в asynctask, но обновите свой arraylist или что вы используете в методе обратного вызова анимации . Во-вторых, если у вас есть общее представление о том, сколько времени требуется для завершения анимации, вы можете применить обработчик с таймером и попытаться сопоставить обе операции, вызвав анимацию с задержкой. Аналогичным образом вы можете использовать широковещательный приемник или интерфейс, если операция пользовательского интерфейса распространяется на действия.
Ответ №3:
вы можете реализовать onProgressUpdate()
метод AsyncTask
, затем в вашем doInBackground()
вызове publishProgress()
вы можете обновить свой пользовательский интерфейс в onProgressUpdate()