Android Marshmallow:在 运行 时更改权限会导致应用程序崩溃
Android Marshmallow: Changing permissions at run time crashes app
Marshmallow 已重新设计获取权限。所以在调用需要权限的方法之前处理了权限并且它工作正常,但它在以下情况下崩溃:
第 1 步:打开应用并授予所有必要的权限
第 2 步:单击主页按钮(因此应用程序处于后台)
第 3 步:在设置中手动更改权限
第 4 步:从多任务启动应用程序,现在由于应用程序上下文变得无效而崩溃
观察到应用程序再次创建,不明白为什么会这样。欢迎任何纠正此问题的建议!
这是因为 Marshmallow 添加了额外的功能。您需要在运行时向用户请求。为此,请使用我制作的 class。然后在任何需要的地方使用它
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
申请权限,你可以改成任何需要的。
Observed that app gets created again, don't understand why this
happens. Any suggestions to rectify this issue would be welcome!
因为当权限改变时,应用程序"state"应该失效。正确的做法是销毁根上下文,即应用程序本身。
每次查询需要这些权限的API方法时,您都必须检查权限授予状态。您不能依赖某些 SharedPreferences
标志来指示“ 用户已授予入职权限,好的,让我们玩得开心 ”。在这方面让你的应用程序无状态。
例如,您可以创建一些 BaseActivity/BaseFragment 或实用程序并将所有检查逻辑移到其中。
首先定义一个布尔值
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);
}
}
您可以参考以上代码并在您的应用中实现。
Marshmallow 已重新设计获取权限。所以在调用需要权限的方法之前处理了权限并且它工作正常,但它在以下情况下崩溃:
第 1 步:打开应用并授予所有必要的权限
第 2 步:单击主页按钮(因此应用程序处于后台)
第 3 步:在设置中手动更改权限
第 4 步:从多任务启动应用程序,现在由于应用程序上下文变得无效而崩溃
观察到应用程序再次创建,不明白为什么会这样。欢迎任何纠正此问题的建议!
这是因为 Marshmallow 添加了额外的功能。您需要在运行时向用户请求。为此,请使用我制作的 class。然后在任何需要的地方使用它
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
申请权限,你可以改成任何需要的。
Observed that app gets created again, don't understand why this happens. Any suggestions to rectify this issue would be welcome!
因为当权限改变时,应用程序"state"应该失效。正确的做法是销毁根上下文,即应用程序本身。
每次查询需要这些权限的API方法时,您都必须检查权限授予状态。您不能依赖某些 SharedPreferences
标志来指示“ 用户已授予入职权限,好的,让我们玩得开心 ”。在这方面让你的应用程序无状态。
例如,您可以创建一些 BaseActivity/BaseFragment 或实用程序并将所有检查逻辑移到其中。
首先定义一个布尔值
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);
}
}
您可以参考以上代码并在您的应用中实现。