Повторный запрос разрешения после изменения ориентации

Поскольку Android SDK 23 дает пользователям возможность запретить пользователям доступ к определенным функциям, я хотел бы обновить одно из своих приложений, чтобы запросить разрешения, как описано здесь: https://developer.android.com/preview/features/runtime-permissions.html.

В одном из действий я вставляю SupportMapFragment. Чтобы заставить его работать, вам необходимо иметь разрешение WRITE_EXTERNAL_STORAGE, поэтому я запрашиваю его при запуске операции, которая приводит к созданию диалога запроса на доступ.

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

Есть ли способ избавиться от начатого диалога?

Ответ 1

Как сообщает CommonsWare в своем comment, лучшим решением является поместить логическое значение в файл savedInstanceState-Bundle, чтобы узнать, открыто ли диалоговое окно.

Пример:

// true if dialog already open
private boolean alreadyAskedForStoragePermission = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(savedInstanceState != null) {
        alreadyAskedForStoragePermission = savedInstanceState.getBoolean(STORAGE_PERMISSION_DIALOG_OPEN_KEY, false);
    }
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    outState.putBoolean(KEY, alreadyAskedForStoragePermission);
}

private void checkStoragePermission(){
    if(alreadyAskedForStoragePermission){
        // don't check again because the dialog is still open
        return;
    }

    if(ActivityCompat.checkSelfPermission(this, STORAGE_PERMISSIONS[0]) != PackageManager.PERMISSION_GRANTED){
        // the dialog will be opened so we have to keep that in memory
        alreadyAskedForStoragePermission = true;
        ActivityCompat.requestPermissions(this, STORAGE_PERMISSIONS, STORAGE_PERMISSION_REQUEST_CODE);
    } else {
        onStoragePermissionGranted();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode){
        case STORAGE_PERMISSION_REQUEST_CODE:
            // the request returned a result so the dialog is closed
            alreadyAskedForStoragePermission = false;

            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                onStoragePermissionGranted();
            }

            break;
    }
}

Ответ 2

Как упоминалось в @user1991776, на самом деле есть недокументированная дополнительная информация, содержащая, есть ли в настоящий момент диалоговое окно разрешения, в Activity:

private static final String HAS_CURENT_PERMISSIONS_REQUEST_KEY =
        "android:hasCurrentPermissionsRequest";

Однако есть лучший способ. Когда вы запрашиваете диалог разрешения во второй раз (из-за поворота), Activity автоматически отменяет старое диалоговое окно, вызывая onRequestPermissionResult() с пустыми массивами:

public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
    if (mHasCurrentPermissionsRequest) {
        Log.w(TAG, "Can reqeust only one set of permissions at a time");
        // Dispatch the callback with empty arrays which means a cancellation.
        onRequestPermissionsResult(requestCode, new String[0], new int[0]);
        return;
    }
    Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
    startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
    mHasCurrentPermissionsRequest = true;
}

Или, конечно, это поведение не документировано, потому что это Android, и кто хочет документировать сложное поведение?

В любом случае вы всегда можете запрашивать разрешения в onCreate(), а затем игнорировать вызовы onRequestPermissionsResult() с массивами permissions с нулевой длиной.

Ответ 3

Я предполагаю, что это системный диалог, который вы не можете контролировать. Вместо этого вы можете предотвратить перезагрузку своей активности, если вы перевернете свое устройство.