понедельник, октября 10, 2011

ProgressDialog, Back и handler


У меня есть activity. На ней имеется кнопка, инициализирующая обращение к какому-то объекту, выполняющему длительную обработку запроса. Перед началом обработки activity показывает progressDialog.
В качестве одного из параметров метода вызываемого объекта передаётся handler. После окончания обработки запроса сервер отправит этому handler сообщение, уведомляя о завершении работы, и передавая, возможно, результат при помощи Bundle.

handler, получив сообщение, спрячет progressDialog и покажет alertDialog, который и сообщит о завершении обработки запроса.

Пусть логика взаимодействия подразумевает возможность не дожидаться завершения запроса. progressDialog в таком случае логично сделать сancelable.

Теперь нужно сделать так, чтобы при нажатии пользователем на Back во время отображения progressDialog, не только прятался бы сам progressDialog, но и завершалась бы текущая activity.  В противном случае получается так, что progressDialog больше не показывается, но по-прежнему продолжает показываться та же activity. Что смутительно.

Для этого нужно диалогу сказать, что делать в случае его отмены:


@Click
public void callServerButton() {
ProgressDialog dialog = new ProgressDialog(this);
dialog.setTitle("Подождите");
dialog.setMessage("Запрос обрабатывается...");
dialog.setCancelable(true);
dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {

@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
dialog.cancel();
finish();
return true;
}
return false;
}
});

activeDialog = dialog;
activeDialog.show();

Server server = new Server();
server.doIt(serverHandler);
}

Теперь во время отображения progressDialog в случае нажатия на Back закроется не только сам диалог, но и activity, чего и добивались.

Теперь возникает другой вопрос - пусть пользователь, не дождавшись завершения работы сервера, нажал Back, в результате activity скрылась. Пользователь продолжает работать с приложением. А в это время сервер закончил обработку запроса и отправил сообщение handler.

handler получает сообщение, пытается создать и отобразить alertDialog. Но диалог использует контекст той activity, которой уже нет - в результате получаем завершение работы приложения и stacktrace для дальнейшего изучения.

Чтобы избежать такой проблемы добавляем какой-нибудь признак в activity. Доопределяем onStop() так, чтобы при выполнении этого метода устанавливалось бы значение этого признака. После этого говорим handler - показывай AlertDialog только в том случае, если значение признака не установлено.

Разумеется, при таком решении пользователь лишается возможности узнать, чем же закончилось выполнение запроса. Для не критичных случаев - это нормально. Например, пользователь захотел посмотреть значения курсов валют, но, не дождавшись, передумал.

Если же происходит что-то, требующее уведомления пользователя, то в данном решении нужно посмотреть в сторону Toast или Notifications.

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