Понимание метода разрешения Android 6

Я пытаюсь взять изображение из Галереи и настроить его на просмотр изображения, но в Android 6 есть некоторые проблемы с разрешением. Ниже приведен способ запроса разрешения. Должен ли я запрашивать чтение внешнего хранилища или запись во внешнее хранилище?

Вот что я сделал до сих пор:

    private static final int READ_CONTACTS_PERMISSIONS_REQUEST = 1;


    public void getPermissionToReadExternalStorage() {

    if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {

        if (shouldShowRequestPermissionRationale(
                Manifest.permission.READ_EXTERNAL_STORAGE)) {

            requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    READ_CONTACTS_PERMISSIONS_REQUEST);
        }}}
    @Override
            public void onRequestPermissionsResult(int requestCode,
                                                   @NonNull String permissions[],
                                                   @NonNull int[] grantResults){
                // Make sure it's our original READ_CONTACTS request
                if (requestCode == READ_CONTACTS_PERMISSIONS_REQUEST) {
                    if (grantResults.length == 1 &&
                            grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        Toast.makeText(getActivity(), "Read Contacts permission granted", Toast.LENGTH_SHORT).show();

                    } else {
                        Toast.makeText(getActivity(), "Read Contacts permission denied", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
                }
            }

Теперь мой прослушиватель кликов для выбора данных из галереи:

     pro.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            intent.setType("image/*");
            if (android.os.Build.VERSION.SDK_INT >= 23) {
                getPermissionToReadExternalStorage();
                if (getPermissionToReadExternalStorage () this???? <==)
                startActivityForResult(Intent.createChooser(intent, "Select Picture"), 0);
            } else {
                startActivityForResult(Intent.createChooser(intent, "Select Picture"), 0);
        }}

    });
    return v;
}

Теперь я хочу получить результат метода getPermissionToReadExternalStorage(), чтобы я мог запустить Activity для выбора галереи для Android 6. Как я могу получить результат класса void? И еще одно: нужно ли мне писать метод для каждого разрешения, которое запрашивает мое приложение?


person Umer Asif    schedule 10.12.2015    source источник


Ответы (3)


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

Во-первых, создайте класс Activity с помощью этого кода (вы можете расширить любой нужный вам вид активности, например AppCompatActivity):

public abstract class PermissionActivity extends AppCompatActivity {

    private final ArrayList<PermissionListener> permissionListeners = new ArrayList<>();

    @SuppressWarnings("unused")
    public void requestPermissions(int requestCode, String[] requestPermissions, PermissionListener permissionListener) {
        requestPermissions(requestCode, requestPermissions, null, permissionListener);
    }

    @SuppressWarnings("unused")
    public void requestPermissions(final int requestCode, String[] requestPermissions, String message, final PermissionListener permissionListener) {
        final int[] grantResults = new int[requestPermissions.length];

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            ArrayList<String> list_notGranted = new ArrayList<>();

            for (String requestPermission : requestPermissions)
                if (ContextCompat.checkSelfPermission(this, requestPermission) != PackageManager.PERMISSION_GRANTED)
                    list_notGranted.add(requestPermission);

            if (list_notGranted.size() > 0) {
                permissionListeners.add(permissionListener);

                requestPermissions = list_notGranted.toArray(new String[list_notGranted.size()]);

                if (message != null) {
                    boolean shouldShowRequestPermissionRationale = false;

                    for (String permission : requestPermissions)
                        if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
                            shouldShowRequestPermissionRationale = true;
                            break;
                        }

                    if (shouldShowRequestPermissionRationale) {
                        final String[] f_requestPermissions = requestPermissions;

                        AlertDialog.Builder builder = new AlertDialog.Builder(this);

                        builder.setMessage(message);

                        DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() {

                            @TargetApi(Build.VERSION_CODES.M)
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                switch (which) {
                                    case DialogInterface.BUTTON_POSITIVE:
                                        PermissionActivity.super.requestPermissions(f_requestPermissions, requestCode);
                                        break;
                                    default:
                                        for (int i = 0; i < grantResults.length; i++)
                                            grantResults[i] = PackageManager.PERMISSION_DENIED;

                                        if (permissionListener != null)
                                            permissionListener.onResult(requestCode, f_requestPermissions, grantResults);
                                        break;
                                }
                            }
                        };

                        builder.setPositiveButton("OK", onClickListener);
                        builder.setNegativeButton("Cancel", onClickListener);

                        builder.show();
                    } else {
                        super.requestPermissions(requestPermissions, requestCode);
                    }
                } else {
                    super.requestPermissions(requestPermissions, requestCode);
                }
            } else {
                for (int i = 0; i < grantResults.length; i++)
                    grantResults[i] = PackageManager.PERMISSION_GRANTED;

                if (permissionListener != null)
                    permissionListener.onResult(requestCode, requestPermissions, grantResults);
            }
        } else {
            if (permissionListener != null) {
                for (int i = 0; i < grantResults.length; i++)
                    grantResults[i] = PackageManager.PERMISSION_GRANTED;

                permissionListener.onResult(requestCode, requestPermissions, grantResults);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
        for (Iterator<PermissionListener> it = permissionListeners.iterator(); it.hasNext(); ) {
            PermissionListener permissionListener = it.next();
            if (permissionListener.onResult(requestCode, permissions, grantResults)) {
                it.remove();
            }
        }
    }

    public interface PermissionListener {

        boolean onResult(int requestCode, String[] requestPermissions, int[] grantResults);

    }
}

Если вы хотите запрашивать разрешения у фрагментов, добавьте этот класс:

public class PermissionFragment extends Fragment {

    @SuppressWarnings("unused")
    public void requestPermissions(int requestCode, String[] requestPermissions, PermissionActivity.PermissionListener permissionListener) {
        requestPermissions(requestCode, requestPermissions, null, permissionListener);
    }

    @SuppressWarnings("unused")
    public void requestPermissions(final int requestCode, String[] requestPermissions, String message, PermissionActivity.PermissionListener permissionListener) {
        ((PermissionActivity) getActivity()).requestPermissions(requestCode, requestPermissions, message, permissionListener);
    }
}

Ваши Действия и Фрагменты должны расширять эти классы вместо стандартных.

Теперь вы готовы запросить разрешения, вызвав метод:

requestPermissions(int requestCode, String[] requestPermissions, PermissionListener permissionListener)

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

requestPermissions(int requestCode, String[] requestPermissions, String message, PermissionListener permissionListener)

НЕ ПРОПУСТИТЕ МЕТОД ПО УМОЛЧАНИЮ, КОТОРЫЙ

// DON'T USE THIS ONE!
requestPermissions(String[] requestPermissions, int requestCode)
// DON'T USE THIS ONE!

Вот пример запроса контактов:

private void requestAndLoadContacts() {
    String[] permissions = new String[]{Manifest.permission.READ_CONTACTS};

    requestPermissions(REQUEST_PERMISSIONS_CONTACTS, permissions, "Read contacts permission is required for the app to work!", new PermissionListener() {

        @Override
        public boolean onResult(int requestCode, String[] requestPermissions, int[] grantResults) {
            // Check if the requestCode is ours
            if (requestCode == REQUEST_PERMISSIONS_CONTACTS) {
                // Check if the permission is correct and is granted
                if (requestPermissions[0].equals(Manifest.permission.READ_CONTACTS) && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // Permission granted
                    // Calling a method to actually load the contacts
                    loadContacts();
                } else {
                    // Permission not granted
                    Toast.makeText(MainActivity.this, "Access denied!", Toast.LENGTH_SHORT).show();
                }

                return true;
            }

            return false;
        }
    });
}

ПРИМЕЧАНИЕ. При реализации PermissionListener не забудьте вернуть true, если код запроса является правильным, иначе PermissionListener не будет удален. strong> из ArrayList, и вы, скорее всего, получите небольшую утечку памяти.

person geNia    schedule 11.12.2015
comment
Спасибо, чувак. Я тебя понял. - person Umer Asif; 11.12.2015
comment
Хорошая идея! Можно ли улучшить использование ContextCompat, которое обрабатывает старые версии Android? Благодарю вас! - person Gilian; 14.06.2016
comment
Но PermissionListeners.remove(permissionListener); не будет вызывать исключение ConcurrentModificationException? - person Gilian; 14.06.2016
comment
@Джилиан Так и будет. С тех пор я много улучшил этот код. Собираюсь обновить ответ в ближайшее время. - person geNia; 14.06.2016
comment
@geNia Хорошее решение, мне понравилось использовать метод shouldShowRequestPermissionRationale() для использования сообщений, еще раз спасибо! - person Gilian; 14.06.2016

ИЗМЕНИТЬ

Я переписал код и разместил его в другом ответе.

Старый ответ:

Да, вы должны проверять и спрашивать разрешения каждый раз.

Обычно я пишу код так:

private int requestPermissionCode;
private Runnable requestPermissionRunnable;

private void runPermissionCode(String requestPermission, int requestCode, Runnable codeToRun) {
    if (android.os.Build.VERSION.SDK_INT >= 23) {
        if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

            requestPermissionCode = requestCode;
            requestPermissionRunnable = codeToRun;

            requestPermissions(new String[]{requestPermission},
                    requestCode);
        }
    } else {
        codeToRun.run();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull String permissions[],
                                       @NonNull int[] grantResults) {
    if (requestCode == requestPermissionCode) {
        if (grantResults.length == 1 &&
                grantResults[0] == PackageManager.PERMISSION_GRANTED) {

            if (requestPermissionRunnable != null)
                requestPermissionRunnable.run();
        } else {
            Toast.makeText(getActivity(), "Permission denied", Toast.LENGTH_SHORT).show();
        }
    } else {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

и запустите его следующим образом:

    runPermissionCode(Manifest.permission.READ_EXTERNAL_STORAGE, READ_CONTACTS_PERMISSIONS_REQUEST, new Runnable() {

        @Override
        public void run() {
            // your code here
        }
    });

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

person geNia    schedule 10.12.2015
comment
но как вы его используете?? или вы используете его, когда пользователь собирается что-то щелкнуть????? Итак, разрешение получено, вы можете выполнять свою задачу.? как бы вы использовали его в моем случае? или любой другой случай, просто покажите мне код со слушателем. - person Umer Asif; 11.12.2015

Инициализировать ваше разрешение

private static final int INITIAL_REQUEST = 1337;
private static final int GET_ACCOUNTS = INITIAL_REQUEST+2;
private static final int LOCATION_REQUEST =INITIAL_REQUEST+3;

private static final String[] INITIAL_PERMS = {
        Manifest.permission.GET_ACCOUNTS,
        Manifest.permission.INTERNET,
        Manifest.permission.ACCESS_FINE_LOCATION
};

Проверить устройство и запросить разрешения

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (!canAccessAccounts()|| !canAccessLocation() ||!canAccessInternet()) {
            requestPermissions(INITIAL_PERMS, INITIAL_REQUEST);
        }
    }

Проверить разрешение предоставлено или нет

private boolean canAccessAccounts() {

    return (hasPermission(Manifest.permission.GET_ACCOUNTS));
}
private boolean canAccessLocation() {

    return (hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
}
private boolean canAccessInternet() {
    return (hasPermission(Manifest.permission.INTERNET));
}
private boolean hasPermission(String perm) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return (PackageManager.PERMISSION_GRANTED == checkSelfPermission(perm));
    }
    return (true);
}

Обновить разрешения и метод проверки разрешений onRequestPermissionsResult

 void UpdatePermissions(){

    canAccessInternet();
    canAccessLocation();
    canAccessInternet();
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    UpdatePermissions();
    switch(requestCode) {
        case GET_ACCOUNTS:
            if (canAccessAccounts()) {

            }
            else {

            }
            break;

        case LOCATION_REQUEST:
            if (canAccessLocation()) {

            }
            else {

            }
            break;

        case INITIAL_REQUEST:
            if(canAccessInternet()){

            }else {

            }
            break;

    }
}
person Naeem Ibrahim    schedule 10.02.2016