Android - dismissDialog не отклоняет диалоговое окно

Я публикую это, потому что на устройстве HUAWAI Prism II Android 4.1.1 (API 16) игра, над которой я работаю ( http://www.playlunapuma.com ) было следующее раздражающее поведение:

Я отображаю свое главное меню, которое имеет некоторую анимацию в SurfaceView и воспроизводит звук время от времени. Устройство отключается, затемняется и затем гаснет. Он вызывает onDestroy для моей Активности, а затем при выключенном экране снова создает мою Активность, вызывая onCreate! Так что проблема в том, что моя анимация и звуки воспроизводятся при выключенном экране. Я действительно хочу, чтобы цикл анимации вообще не работал, если экран выключен. Приемники вещания не работают, потому что я не могу сохранить состояние с момента последнего отключения экрана. Я думал о некоторых хакерских атаках со статическими логическими значениями, но это только казалось, что kluge может не работать и иметь ужасные крайние случаи. Экран уже выключен, когда моя активность снова создается, поэтому я не получу событие через приемник вещания, что мой экран выключен.

Я решил это, используя и широковещательный приемник, и код, указанный выше.

В моем onCreate я создаю широковещательный приемник. Это будет контролировать мой цикл анимации при включении и выключении экрана.

if (mScreenReceiver == null) {
    mScreenIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
    mScreenIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
    mScreenReceiver = new ScreenReceiver();
    registerReceiver(mScreenReceiver, mScreenIntentFilter);
}
public class ScreenReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {                
            controlAnimLoop(false, false, true);
        } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            controlAnimLoop(false, false, false);
        }
    }

}

В моем controlAnimLoop я проверяю isScreenOn, это код:

private boolean isScreenOn() {
    if (android.os.Build.VERSION.SDK_INT >= 20) {
        // I'm counting                                                                                                                
        // STATE_DOZE, STATE_OFF, STATE_DOZE_SUSPENDED                                                                                 
        // all as "OFF"                                                                                                                

        DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
        for (Display display : dm.getDisplays ()) {
            if (display.getState () == Display.STATE_ON ||
                display.getState () == Display.STATE_UNKNOWN) {
                return true;
            }
        }

        return false;
    }

    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);

    return powerManager.isScreenOn();
}

22
задан Shruti 14 June 2012 в 09:04
поделиться

4 ответа

Помните, что каждый раз, когда вы меняете ориентацию, создается новый экземпляр вашего Activity (и, следовательно, вашего Dialog через onCreateDialog ) создан. Вы можете проверить это, добавив оператор журнала в любой из конструкторов.

Хотя трудно сказать, не взглянув на свой код, я предполагаю, что вы вызываете dismissDialog в более старом экземпляре вашего Действие .

Рассмотрим следующее Действие , которое просто показывает пустой Диалог при нажатии кнопки и запускает TimerTask , чтобы закрыть его. через 10 секунд:

public class Test extends Activity {

    private Dialog dialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        setContentView(R.layout.test);
        Button btn = (Button) findViewById(R.id.testButton);
        btn.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                new Timer().schedule(new TimerTask() {
                    @Override public void run() { dialog.dismiss(); }
                }, 10000);
                Test.this.showDialog(1);
            }
        });
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        if(id == 1) {
            if(dialog == null) { dialog = new Dialog(this); }
            return dialog;
        }
        return super.onCreateDialog(id);
    }
}

В этом коде есть проблема, аналогичная описанной вами: если - в течение 10 секунд - ориентация изменилась, Диалог никогда не закрывается. Почему? Потому что в то время TimerTask является запускается , совершенно другой набор экземпляров Test и Dialog был создан (во время изменения ориентации) и переменная экземпляра диалогового окна диалогового окна TimerTask ссылается на экземпляр Test , который отличается от того, который в настоящее время активен на экран.

Очевидно, есть несколько способов решения этой проблемы (в основном в зависимости от вашего приложения), один быстрый (грязный?) способ исправить приведенный выше код - просто сделать поле dialog полем static :

private static Dialog dialog;
0
ответ дан 29 November 2019 в 05:29
поделиться

Недавно я тоже столкнулся с этой проблемой. У меня есть приложение с множеством действий, требующих доступа к глобальным объектам (соединения с базами данных, списки данных и т. Д.), Поэтому я переопределил класс Application. Для этого я понял, что все, что мне нужно, - это ссылка на последний экземпляр диалога прогресса в моем исполняемом файле, который я использовал, чтобы закрыть диалог. Это то, что я придумал, и он изящно переживает переориентацию телефона:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.preferences);

    mHandler = new Handler();
    mApplication = (MyApplication)getApplication();

    mFileStorage = (CheckBoxPreference)getPreferenceScreen().findPreference("fileStorage");

    mProgressDialog = new ProgressDialog(this);

    mProgressDialog.setTitle("Location Update");
    mProgressDialog.setMessage("Moving databases to new storage location.");
    mProgressDialog.setIndeterminate(true);
    mProgressDialog.setCancelable(false);
    mProgressDialog.setCanceledOnTouchOutside(false);

    mApplication.setProgressDialog(mProgressDialog);
}

@Override
protected void onResume() {
    super.onResume();

    mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    mPreferences.registerOnSharedPreferenceChangeListener(this);

    if (sUpdateThread != null && sUpdateThread.isAlive()) {
        mProgressDialog.show();
    }
}

@Override
protected void onPause() {
    super.onPause();

    mPreferences.unregisterOnSharedPreferenceChangeListener(this);

    if (sUpdateThread != null && sUpdateThread.isAlive()) {
        mProgressDialog.hide();
        mApplication.setProgressDialog(null);
    }
}

.... здесь случайные вещи ....

private Runnable showProgressRunnable = new Runnable() {
    public void run() {
        mProgressDialog.show();
    }
};

private Runnable hideProgressRunnable = new Runnable() {
    public void run() {
        if (mApplication.getProgressDialog() != null) {
            mApplication.getProgressDialog().dismiss();
        }
    }
};

Мой поток выполняет mHandler.post (showProgressRunnable) при запуске задачи, а затем выполняет mHandler . post (hideProgressRunnable) после завершения задачи. Поскольку ссылка на последний ProgressDialog теперь хранится в классе Application, я могу надежно закрыть его, так как я больше не держусь за ссылку на старый объект.

Ссылка для потомков: http: // developer. android.com/reference/android/app/Application.html

4
ответ дан 29 November 2019 в 05:29
поделиться

После поиска на всевозможных форумах, я сделал следующее:

Я вызываю showDialog(MyDialogID) И dismissDialog(MyDialogId) из метода handleMessage(myMessage) из моего обработчика.

До этого я вызывал showDialog в своем onCreate()-методе и пытался закрыть диалог в handle-Message. Почему это решило проблему, я не могу сказать.

0
ответ дан 29 November 2019 в 05:29
поделиться

Я столкнулся с этим при отображении диалогового окна в переопределении onCreate для Activity. Попробуйте вместо этого переместить код, вызывающий отображение диалогового окна, в переопределение onPostCreate. Мне кажется, это работает.

6
ответ дан 29 November 2019 в 05:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: