Android Marshmallow: изменение разрешений во время выполнения приложения вылетает

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

Шаг 1: Открыл приложение и дал все необходимые разрешения

Шаг 2. Нажмите кнопку "Домой" (приложение находится в фоновом режиме).

Шаг 3: Вручную изменили разрешения в настройках

Шаг 4: Запустил приложение из многозадачности, теперь оно вылетает из-за того, что контекст приложения становится недействительным

Заметил, что приложение создается снова, не понимаю, почему это происходит. Любые предложения по исправлению этой проблемы будут приветствоваться!

Ответ 1

Это из-за дополнительных функций, добавленных из Marshmallow. Вы должны запрашивать у пользователя во время выполнения. Для этого используйте этот класс, который я сделал. Затем используйте его по мере необходимости

public class AppPermission {

    public static boolean isMarshmallowPlusDevice() {
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1;
    }

    @TargetApi(Build.VERSION_CODES.M)
    public static boolean isPermissionRequestRequired(Activity activity, @NonNull String[] permissions, int requestCode) {
        if (isMarshmallowPlusDevice() && permissions.length > 0) {
            List<String> newPermissionList = new ArrayList<>();
            for (String permission : permissions) {
                if (PackageManager.PERMISSION_GRANTED != activity.checkSelfPermission(permission)) {
                    newPermissionList.add(permission);
                }
            }
            if (newPermissionList.size() > 0) {
                activity.requestPermissions(newPermissionList.toArray(new String[newPermissionList.size()]), requestCode);
                return true;
            }
        }
        return false;
    }
}

Затем поместите этот код, где вам требуется разрешение от пользователя.

if (!AppPermission.isPermissionRequestRequired(SignInActivity.this, new String[]{"android.permission.GET_ACCOUNTS"},
        REQUEST_APP_PERMISSION)) {
    // Your code if permission available
}

После этого в вашем Fragment или Activity введите этот код -

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case REQUEST_APP_PERMISSION:
            for (int i = 0; i < permissions.length; i++) {
                String permission = permissions[i];
                int grantResult = grantResults[i];
                switch (permission) {
                    case "android.permission.GET_ACCOUNTS":
                        if (PackageManager.PERMISSION_GRANTED == grantResult) {
                            // Your code
                        }
                        break;
                }
            }
            break;
    }
}

Вышеприведенный код предназначен для разрешения запроса для GET_ACCOUNTS, вы можете изменить его на все, что требуется.

Ответ 2

Наблюдалось, что приложение снова создается, не понимает, почему это случается. Любые предложения по исправлению этой проблемы приветствуются!

Поскольку при изменении разрешений приложение "состояние" должно быть недействительным. Правильный способ сделать это - это разрушить корневой контекст, который является самим приложением.

Вы должны проверять статус предоставленных разрешений каждый раз, когда вы запрашиваете методы API, требующие этих разрешений. Вы не можете полагаться на некоторый флаг SharedPreferences, указывающий, что "пользователь предоставил разрешения в onboarding, хорошо, позволяет получать удовольствие". Сделайте это приложение без гражданства в этом отношении.

Например, вы можете создать BaseActivity/BaseFragment или Utility и переместить туда всю проверяющую логику.

Ответ 3

Определить булево значение сначала

 private boolean isPermissionGranted = false;

И затем проверьте, разрешено ли разрешение:

if (!isPermissionGranted) {
        checkPermission();
    }

Фактический код для проверки разрешения времени выполнения выглядит следующим образом:

private void checkPermission() {
    int hasPermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.CAMERA);
    int hasWritePermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (hasPermission != PackageManager.PERMISSION_GRANTED && hasWritePermission != PackageManager.PERMISSION_GRANTED) {
        if (!ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.CAMERA) && !ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            showMessage(getString(R.string.allow_access_to_camera_external_storage),
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                    REQUEST_CODE_ASK_PERMISSIONS);
                        }
                    });
            return;
        }
        ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_CODE_ASK_PERMISSIONS);
        return;
    } else {
        isPermissionGranted = true;
    }
}

private void showMessage(String message, DialogInterface.OnClickListener       listener) {
    new AlertDialog.Builder(UserProfile.this)
            .setMessage(message)
            .setPositiveButton(R.string.ok, listener)
            .setNegativeButton(R.string.cancel, null)
            .create()
            .show();
}

  @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_ASK_PERMISSIONS:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                isPermissionGranted = true;

            } else {
                isPermissionGranted = false;
                Toast.makeText(UserProfile.this, R.string.permission_denied, Toast.LENGTH_SHORT)
                        .show();
            }
            break;

        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

Вы можете взять ссылку из кода выше и реализовать его в своем приложении.