Как организовать длительные (отнимающие много времени) действия на Android?
-
19-09-2019 - |
Вопрос
Например, мы находимся в SomeActivity, и в activity есть кнопка, которая вызывает перемещение файлов из одного каталога в другой (давайте назовем это job).
На BlackBerry я бы:
- нажмите на всплывающее окно (Диалоговое окно), которое нельзя отменить, со словами "Пожалуйста, подождите ...".
- запустите поток, который выполняет задание
- по завершении потока закройте всплывающее окно
Такой подход на 99,99% может гарантировать, что мы останемся на том же экране после завершения задачи, пользователь просто увидит всплывающее окно и будет ждать завершения задания.Вращение устройства или что-то еще не нарушает желаемый рабочий процесс.
На Android все меняется.Я знаю, что есть AsyncTask, который, вероятно, предусмотрен для решения моего дела.Есть даже хороший пример о том, как его следует использовать.Но поскольку нет гарантии того, как долго будет жить экземпляр Activity, AsyncTask следует отменить в onSaveInstanceState (и перезапустить в onRestoreInstanceState).Это означает, что при использовании AsyncTask нет никакой гарантии, что мы сможем полностью выполнить задание после его запуска.В некоторых случаях при отправке http post-запроса для создания пользователя я бы не хотел получать сообщение "пользователь уже существует для этого входа" при повторном запуске AsyncTask.Это возможно, поскольку AsyncTask может быть прерван, когда запрос уже отправлен (и сервер фактически выполняет свою работу - создает нового пользователя), но AsyncTask отменяется до того, как мы получили ответ.
Есть ли какое-либо решение на Android для получения BB-подобного поведения, указанного выше?
Решение 3
В мае 2010 года Google выпустила новый сеанс ввода-вывода под названием Разработка клиентских приложений Android REST это объясняет, как достичь именно того, о чем я просил.
Оказалось, что вопрос довольно сложный, поэтому простого и быстрого решения не существует.Решение требует глубоких знаний платформы / API Android.Это цена, обусловленная гибкостью жизненного цикла процесса приложения / Активности.
Я чувствую некоторую странность в том, почему эта информация не была представлена с самой первой версии Android.Похоже, Google знала, как писать приложения без ошибок на 100%, но по каким-то маркетинговым причинам не разделяла этот подход.Только представьте, сколько глючных приложений было написано к маю 2010 года.
В любом случае, я рад, что теперь у меня есть то, что мы называем подходом наилучшей практики.
Другие советы
Но поскольку нет никакой гарантии того, как долго экземпляр деятельности будет жить, асинктаска должна быть отменена в OnsaveInstanceTate (и перезапустится на OnRestoreInstancestate).
Или им будет управлять Service
.
Если ваша активность хочет оставаться на экране, вы можете просто запустить поток следующим образом:
final File fromFile = ...;
final File toFile = ...;
new Thread() {
@Override
public void run() {
// do something with fromFile, toFile
}
}.start();
Таким образом, GUI-Thread готов выполнять другие задачи, например, отображать
android.app.ProgressDialog
Также рассмотрите возможность сделать диалог неотменяемым с помощью
ProgressDialog.setCancelable(false);
Таким образом, пользователь может выйти только с помощью клавиши HOME, о которой вы получите уведомление, когда
Activity.onPause()
называется.Кроме того, вы можете захотеть изучить Wakelocks, чтобы экран не стал черным, а ваше приложение не перешло в фоновый режим, где оно может быть убито.Вы бы сделали это в теме:
PowerManager pm = (PowerManager) ivContext.getSystemService(Context.POWER_SERVICE);
Wakelock wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyApp");
wakeLock.acquire();
// ... copy stuff ...
wakeLock.release();
Конечно, вам также придется отключить WakeLock, когда пользователь уходит с помощью клавиши HOME.
Наконец, если вы хотите вызвать GUI-Elements из своего фонового потока, это будет работать только в том случае, если поток является частью GUI-Event-Loop, как и обычный поток, в котором вы работаете, при вызове on... -Методы.Для этого ваш фоновый поток должен будет выполнить обратный вызов GUI-потока через обработчик.Так:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.v(TAG, "Got Message "+msg.what); // prints: Got Message 77
// ... do GUI actions ...
}
};
// ... in Thread ...
int lvInfo = 77;
mHandler.sendEmptyMessage(lvInfo);
Вы даже можете поместить объекты в сообщение следующим образом:
Message txtMsg = Message.obtain();
textMsg.obj = "Hello World";
mHandler.sendMessage(lvTextMsg);