10

Ponieważ pakiet SDK Android 23 daje użytkownikom możliwość odmowy dostępu aplikacji do niektórych funkcji, chciałem zaktualizować jedną z moich aplikacji, aby uzyskać uprawnienia, jak opisano tutaj: https://developer.android.com/preview/features/runtime-permissions.html.Powielanie prośby o zgodę po zmianie orientacji

W jednej z czynności umieszczam SupportMapFragment. Aby to zadziałało, musisz mieć uprawnienie WRITE_EXTERNAL_STORAGE, dlatego żądam go, gdy uruchomię działanie, co spowoduje utworzenie okna żądania uprawnień.

Problem polega na tym, że gdy okno dialogowe jest nadal otwarte i obracam urządzenie, działanie zostanie ponownie uruchomione i zostanie otwarte nowe okno dialogowe żądania uprawnień, podczas gdy stare nadal będzie dostępne. Rezultatem są dwa z tych dialogów jeden na drugim i tylko jeden z nich jest użyteczny.

Czy istnieje sposób na pozbycie się pierwszego okna dialogowego?

+4

Ponieważ nie utworzyłeś okna dialogowego, nie jestem świadomy żadnego sposobu, aby się go pozbyć. Umieść 'boolean' w twoim zapisanym stanie instancji' Bundle', wskazując, że prośba o uprawnienia jest wyjątkowa i nie ponawiaj ponownie żądania pozwolenia. Lub czekaj, aby poprosić o pozwolenie, aż do wprowadzenia jakiejś formy danych użytkownika (np. Dotknięcie elementu paska czynności, który uruchamia 'SupportMapFragment'), w takim przypadku powinieneś być bezpieczny, ponieważ użytkownik nie może ponownie dotknąć tego elementu, podczas gdy okno dialogowe jest widoczny. – CommonsWare

+0

Tak, to prawda. Nie sądziłem, że będzie to opcja, ponieważ "stary" dialog byłby związany tylko ze "starą" działalnością, ale po prostu wypróbowałem ją, a wynik został odebrany przez "nową" aktywność. – Thorben

Odpowiedz

11

Jak powiedział CommonsWare w jego comment najlepszym rozwiązaniem jest umieszczenie wartości boolowskiej w pakiecie savedInstanceState, aby sprawdzić, czy okno dialogowe jest nadal otwarte.

Przykład:

// 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; 
    } 
} 
+0

Wierzę, że istnieje system boolean istnieje w pakiecie savedInstanceState android: hasCurrentPermissionsRequest = true, jeśli okno dialogowe uprawnień jest wyświetlane, ale nie znalazłem żadnej wzmianki w dokumentacji. – user1991776

0

Domyślam się, że to jest dialog systemowy, którego nie możesz kontrolować. Zamiast tego możesz zapobiec ponownemu załadowaniu swojej aktywności po włączeniu urządzenia.

8

Jako @ user1991776 wspomniano tam jest rzeczywiście nieudokumentowane dodatkowy, który zawiera, czy nie istnieje dialog pozwolenie otwarte w momencie, in Activity:

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

Jednak istnieje lepszy sposób. Kiedy złożyć wniosek o pozwolenie dialogowe po raz drugi (ze względu na obrót), Activity automatycznie anuluje stare okna, wywołując swoją onRequestPermissionResult()with empty arrays:

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; 
} 

Albo Oczywiście takie zachowanie isn't documented bo to Android, a kto chce dokumentować złożone zachowanie?

W każdym razie możesz po prostu zawsze żądać uprawnień w onCreate(), a następnie ignorować połączenia z onRequestPermissionsResult() o zerowej długości tablicach permissions.

+0

+ do dokumentowania Androida =) –

Powiązane problemy