Разное поведение Toast в Андроид 2 и 4
Добавлено: 21 май 2013, 00:41
Задача:
Отображать один текущий Toast, который отражает текущее состояние выполняемой операции приложением.
Решение:
Создание BroadcastReceiver'а, который принимает сообщение и генерирует Toast, а так же следит за тем, чтоб в Toast отображался текст именно текущего сообщения.
Проблемы:
Если мы будем просто генерировать при получении сообщения новый Toast, то он встанет в очередь и отобразиться только после окончания времени показа предыдущего Toast. В результате операция будет выполнена, а пользователю будут отображаться Toast, что в принципе будет вводить его в заблуждение, о времени выполнения операции приложением. Исходя из этого, при получении нового сообщения, нам необходимо проверить, отображается в данный момент ли Toast, если да, то закрыть его и бросить новый. Для Андроида до версии 4 решение выгляди следующим образом:
[syntax=java] if(vToast==null) vToast = Toast.makeText(ctx, "", Toast.LENGTH_SHORT);
vToast.cancel();
vToast.setText(sMsg);
vToast.show();[/syntax]
Но в Андроид версии 4 и выше, что-то поменяли и после вызова vToast.cancel(); Toast не будет отображен по вызову vToast.show();. В результате до 4 версии андроида будут отображаться всплывающие сообщения, а начиная с 4 версии код будет работать, но сообщений пользователь не увидит. И это проявление можно увидеть только на реальных девайсах, в эмуляторе будет все ок. после нескольких экспериментов на реальных устройствах у меня получилось отработать это изменения поведения в моём BroadcastReceiver'е.
Готовый код ресивера:
[syntax=java]public class BroadcastReceiverSyncMsg extends BroadcastReceiver {
private static final boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
private static Toast vToast;
@Override
public void onReceive(Context ctx, Intent intent) {
if(intent!=null){
if(intent.getAction()!=null && intent.getAction().equalsIgnoreCase(IntentKey.KEY_ACTION_SYNC_SEND_MESSAGE)){
String sMsg = intent.getStringExtra(IntentKey.KEY_SYNC_SEND_MESSAGE);
if(sMsg!=null){
if (IS_ICS_OR_LATER && vToast != null) {
// Скрываем и обнуляем прошлый Toast в Андроид 4 и выше.
vToast.cancel();
vToast=null;
}
if(vToast==null) vToast = Toast.makeText(ctx, "", Toast.LENGTH_SHORT);
// Скрываем прошлый Toast в Андроид до 4 версии.
if(!IS_ICS_OR_LATER) vToast.cancel();
// Назначаем новый текст Toast и показываем его.
vToast.setText(sMsg);
vToast.show();
}
}
}
}
}[/syntax]
Отображать один текущий Toast, который отражает текущее состояние выполняемой операции приложением.
Решение:
Создание BroadcastReceiver'а, который принимает сообщение и генерирует Toast, а так же следит за тем, чтоб в Toast отображался текст именно текущего сообщения.
Проблемы:
Если мы будем просто генерировать при получении сообщения новый Toast, то он встанет в очередь и отобразиться только после окончания времени показа предыдущего Toast. В результате операция будет выполнена, а пользователю будут отображаться Toast, что в принципе будет вводить его в заблуждение, о времени выполнения операции приложением. Исходя из этого, при получении нового сообщения, нам необходимо проверить, отображается в данный момент ли Toast, если да, то закрыть его и бросить новый. Для Андроида до версии 4 решение выгляди следующим образом:
[syntax=java] if(vToast==null) vToast = Toast.makeText(ctx, "", Toast.LENGTH_SHORT);
vToast.cancel();
vToast.setText(sMsg);
vToast.show();[/syntax]
Но в Андроид версии 4 и выше, что-то поменяли и после вызова vToast.cancel(); Toast не будет отображен по вызову vToast.show();. В результате до 4 версии андроида будут отображаться всплывающие сообщения, а начиная с 4 версии код будет работать, но сообщений пользователь не увидит. И это проявление можно увидеть только на реальных девайсах, в эмуляторе будет все ок. после нескольких экспериментов на реальных устройствах у меня получилось отработать это изменения поведения в моём BroadcastReceiver'е.
Готовый код ресивера:
[syntax=java]public class BroadcastReceiverSyncMsg extends BroadcastReceiver {
private static final boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
private static Toast vToast;
@Override
public void onReceive(Context ctx, Intent intent) {
if(intent!=null){
if(intent.getAction()!=null && intent.getAction().equalsIgnoreCase(IntentKey.KEY_ACTION_SYNC_SEND_MESSAGE)){
String sMsg = intent.getStringExtra(IntentKey.KEY_SYNC_SEND_MESSAGE);
if(sMsg!=null){
if (IS_ICS_OR_LATER && vToast != null) {
// Скрываем и обнуляем прошлый Toast в Андроид 4 и выше.
vToast.cancel();
vToast=null;
}
if(vToast==null) vToast = Toast.makeText(ctx, "", Toast.LENGTH_SHORT);
// Скрываем прошлый Toast в Андроид до 4 версии.
if(!IS_ICS_OR_LATER) vToast.cancel();
// Назначаем новый текст Toast и показываем его.
vToast.setText(sMsg);
vToast.show();
}
}
}
}
}[/syntax]