仅在Android 6.0中没有此类文件或目录

下面的代码在Marshmallow之前的设备上工作正常但在Marshmallow中没有。

这些是Manifest中的权限

   

这是代码

 public void saveImageToSDCard(Bitmap bitmap) { File myDir = new File( Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), pref.getGalleryName()); myDir.mkdirs(); Random generator = new Random(); int n = 10000; n = generator.nextInt(n); String fname = "Wallpaper-" + n + ".jpg"; File file = new File(myDir, fname); if (file.exists()) file.delete(); try { FileOutputStream out = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); out.flush(); out.close(); Uri uri = getImageContentUri(_context,file); Log.d(TAG, "Wallpaper saved to: " + file.getAbsolutePath()); } catch (Exception e) { e.printStackTrace(); } } 

当我手动允许存储权限时,相同的代码也可以工作

这是Nitesh Pareek给出的解决方案。

 private boolean hasPermissions(Context context, String[] permissions) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) { for (String permission : permissions) { if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } } return true; } String[] PERMISSIONS = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}; if (!hasPermissions(this, PERMISSIONS)) { ActivityCompat.requestPermissions(this, PERMISSIONS, 11); return; } 

从Android 6.0(API级别23)开始,用户在应用程序运行时向应用程序授予权限,而不是在安装应用程序时。

这就是它在pre-lolipop版本中工作的原因,而不是在API 23上。仅在Android Manifest中的权限是不够的,您还需要在运行时添加它们。 请参阅此处了解更多详情。

为marshmallow或更新版本的运行时授予读写权限。 如下所示: –

 String[] PERMISSIONS = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}; if (!hasPermissions(this, PERMISSIONS)) { ActivityCompat.requestPermissions(this, PERMISSIONS, 11); return; } private boolean hasPermissions(Context context, String... permissions) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) { for (String permission : permissions) { if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } } return true; } 

您需要在运行时获取应用程序权限,而不是按照约定在安装/更新时获取

从Android 6.0(API级别23)开始,用户在应用程序运行时向应用程序授予权限,而不是在安装应用程序时。 此方法简化了应用安装过程,因为用户在安装或更新应用时无需授予权限

如需更多帮助: 在运行时请求权限

通过关注文档并在进行一些谷歌搜索之后,最后我编译了下面的代码以有效地处理运行时权限

要使其工作,您需要按照以下说明操作:

调用此方法以检查用户是否授予了存储权限? 如果没有,那么你需要请求它

 public static boolean isStoragePermissionGranted(Activity activity) { boolean flag = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { flag = activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; } return flag; } 

调用此方法以请求存储权限

 public static void requestStoragePermission(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (isStoragePermissionGranted(activity)) { return; } // Fire off an async request to actually get the permission // This will show the standard permission request dialog UI activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_STORAGE_PERMISSION); } } 

在您的活动中实现此方法以处理权限回调的响应

 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case REQUEST_CODE_STORAGE_PERMISSION: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (grantResults.length > 0) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { boolean shouldShowRationale = shouldShowRequestPermissionRationale(permissions[0]); if (!shouldShowRationale) { // user denied flagging NEVER ASK AGAIN, you can either enable some fall back, // disable features of your app or open another dialog explaining again the permission and directing to // the app setting dialogReasonStoragePermissionToSettings(this); } else if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permissions[0])) { // user denied WITHOUT never ask again, this is a good place to explain the user // why you need the permission and ask if he want to accept it (the rationale) dialogReasonStoragePermission(this); } } /*else { // Do on permission granted work here }*/ } } break; } } public static void dialogReasonStoragePermission(final Activity activity) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setMessage(activity.getString(R.string.reason_storage_permission)); builder.setCancelable(false); builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { requestStoragePermission(activity); } }); builder.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); } }); AlertDialog dialog = builder.create(); dialog.show(); } public static void dialogReasonStoragePermissionToSettings(final Activity activity) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setMessage(activity.getString(R.string.reason_storage_permission)); builder.setCancelable(false); builder.setPositiveButton("Go to Settings", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { goToAppDetailsForPermissionSettings(activity); } }); builder.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); } }); AlertDialog dialog = builder.create(); dialog.show(); } private static final int REQUEST_CODE_APP_DETAILS_PERMISSION_SETTING = 3995; private static void goToAppDetailsForPermissionSettings(Activity activity) { Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", activity.getPackageName(), null); intent.setData(uri); activity.startActivityForResult(intent, REQUEST_CODE_APP_DETAILS_PERMISSION_SETTING); } 

我没有为你提供这方面的直接代码,但是这里有一个原因API级别23引入了一个新的Permission结构以获得更多的安全性,这是一个简短但很糟糕的描述,在这里的文档中

从Android 6.0(API级别23)开始,用户在应用程序运行时向应用程序授予权限,而不是在安装应用程序时。 此方法简化了应用安装过程,因为用户在安装或更新应用时无需授予权限。 它还使用户可以更好地控制应用程序的function; 例如,用户可以选择让相机应用程序访问相机,但不能访问设备位置。 用户可以通过转到应用程序的“设置”屏幕随时撤消权限。

代码很好,只需要添加一些额外的内容,即存储的运行时权限

阅读本博客 ,了解有关Runtime Permissions的深入内容,让我对此有一个清晰的了解,希望它也能帮到你。

谢谢