К сожалению, перехватить onExposed
недостаточно. Я обнаружил, что в Blackberry диалоги также являются экранами и даже контекстные меню тоже являются экранами. Они помещаются в верхней части экрана, поэтому вы получаете обратный вызов onExposed при их отклонении.
Хотя во многих случаях все нормально, в других случаях возникает проблема - например, если я должен обновлять содержимое экрана только тогда, когда пользователь возвращается к нему, но не после меню / диалогов, то как мне это сделать? Мой случай, к сожалению, один из них.
Я не нашел документированного способа обнаружения «покрытых» / «непокрытых» событий. Вот мой подход. onCovered
/ onUncovered
обратные вызовы вызываются, когда текущий экран покрывается / открывается другим экраном приложения, но не диалоговыми окнами / меню / виртуальной клавиатурой:
public class MyAppScreen extends MainScreen {
private boolean isCovered;
protected void onExposed() {
Log.d("onExposed");
super.onExposed();
if (isCovered) {
onUncovered();
isCovered = false;
}
}
protected void onObscured() {
Log.d("onObscured");
super.onObscured();
final Screen above = getScreenAbove();
if (above != null) {
if (isMyAppScreen(above)) {
isCovered = true;
onCovered();
}
}
}
private boolean isMyAppScreen(final Screen above) {
return (above instanceof MyAppScreen);
}
protected void onUncovered() {
Log.d("onUncovered");
}
protected void onCovered() {
Log.d("onCovered");
}
protected void onUiEngineAttached(final boolean attached) {
if (attached) {
Log.d("UI Engine ATTACHED");
} else {
Log.d("UI Engine DETACHED");
}
super.onUiEngineAttached(attached);
}
protected void onFocusNotify(final boolean focus) {
if(focus){
Log.d("focus GAINED");
} else {
Log.d("focus LOST");
}
super.onFocusNotify(focus);
}
}
И тест. Попробуйте различные комбинации и посмотрите, какие события вы получите в журнале.
public class TestLifecycle extends MyAppScreen implements FieldChangeListener {
private final ABNTextEdit txt1;
private final ButtonField btn1;
private final ButtonField btn2;
public TestLifecycle() {
final Manager manager = getMainManager();
txt1 = new ABNTextEdit();
manager.add(txt1);
btn1 = new ButtonField("Dialog", ButtonField.CONSUME_CLICK);
btn1.setChangeListener(this);
manager.add(btn1);
btn2 = new ButtonField("Screen", ButtonField.CONSUME_CLICK);
btn2.setChangeListener(this);
manager.add(btn2);
}
public void fieldChanged(final Field field, final int context) {
if (field == btn1) {
Dialog.alert("Example alert");
} else if (field == btn2) {
UiApplication.getUiApplication().pushScreen(new TestLifecycle());
}
}
}
Обновление:
Этот метод имеет ограничение: если новый экран нажимается, когда диалоговое окно или программная клавиатура находится в фокусе, ваш текущий экран будет не получать onCovered
/ onUncovered
уведомление.
Пример A: если у вас есть поле ввода фиксированного размера, и вы нажимаете новый экран, когда пользователь завершает его, ваш текущий экран не будет получать уведомление, если пользователь введет very быстро. Это происходит потому, что в тот момент, когда вы звоните push(newScreen)
и он фактически нажимается, пользователь нажимает на букву в мягкой КБ, и он захватывает фокус. Так называется только onObscured
, но не onCovered
.
Решение: явно скрыть программную клавиатуру до push(newScreen)
.
Пример B: Если у вас есть настроенное диалоговое окно, которое открывает новый экран, а затем закрывает себя, ваш текущий экран не получит уведомление. Это происходит потому, что ваш настроенный диалог не распознается как экран, поэтому вызывается только onObscured
, но не onCovered
.
Решение: в первую очередь закрывает диалоговое окно, возвращающее значение результата, и позволяет вашему экрану выдвигать новый экран на основе этого значения. -ИЛИ- переопределить isMyAppScreen()
для возврата true
также для настраиваемого диалогового окна.