当一个应用卸载之后,内部存储中的这些文件也被删除。在创建内部存储文件的时候将文件属性设置成可读,其他app能够访问自己应用的数据,前提是他知道你这个应用的包名,如果一个文件的属性是私有(private),那么即使知道包名其他应用也无法访问。 内部存储空间十分有限,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。Shared Preferences和SQLite数据库都是存储在内部存储空间上的。内部存储一般用Context来获取和操作。
内部存储的统一路径:/data/user/0/"包名(如:com.example.myapplication)"
获得内部存储路径的方式:
外部存储可能是手机外置的SD卡,不过现在大多数手机后盖都不可能让你轻易拆开的,因为外部存储厂商已经帮配置好了,128G、64G,大部分的容量都是外部存储。
外部存储我们可以在文件管理中,Android/data/包名中找到,而内部存储我们是看不到的。
获得外部存储路径的方式:
在Android Q中引入了分区储存功能,在外部存储设备中为每个应用提供了一个“隔离存储沙盒”。其他应用无法直接访问应用的沙盒文件。由于文件是应用的私有文件,不再需要任何权限即可访问和保存自己的文件。此变更并有助于减少应用所需的权限数量,同时保证用户文件的隐私性。
文件存储在应用私有目录下,在卸载该应用后,系统会清除该应用的目录中的所有文件。有时我们要在卸载后保留这些文件,请将其保存到 MediaStore 中的某个目录下。
访问其他应用创建的文件
只有在满足以下两个条件时,您的应用才能访问其他应用创建的文件:
public String compressImageByQuality(Context Context, Bitmap bitmap, String filename, int quality) {
if (bitmap == null) {
return "";
}
final File f = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/" + filename);
try {
FileOutputStream fos = new FileOutputStream(f);
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, fos);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return f.getAbsolutePath();
}
ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, mode);mode:"r" ,"rw"等等
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap bm = BitmapFactory.decodeFileDescriptor(fileDescriptor);
老版本的方法:
1、直接插入媒体库
MediaStore.Images.Media.insertImage(ContentResolver cr, String imagePath,String name, String description);
通过该方法,提供文件名,图片路径就可以将图片插入媒体库。
2、发送广播
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + filePath))); //Uri.fromFile(new File(filePath))
发送广播方法,让媒体库去扫描你的图片文件,效率差,有延迟。
3、扫描文件方法
MediaScannerConnection.scanFile(getBaseContext(), new String[]{filePath}, new String[]{"image/jpeg"}, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
ToastUtil.shortToast(getBaseContext(),"保存成功");
}
});
同样让媒体库去扫描你的图片文件,比第二效率高效。
上面的三种方法,最近项目实践中,只有第一种生效了,第二、三种尝试了很多次,相册都没看到图片,也可能是我方法不对。但是第一种已经被弃用了。
/**
* Insert an image and create a thumbnail for it.
*
* @param cr The content resolver to use
* @param imagePath The path to the image to insert
* @param name The name of the image
* @param description The description of the image
* @return The URL to the newly created image
* @deprecated inserting of images should be performed using
* {@link MediaColumns#IS_PENDING}, which offers richer
* control over lifecycle.
*/
@Deprecated
public static final String insertImage(ContentResolver cr, String imagePath,
String name, String description) throws FileNotFoundException {
final File file = new File(imagePath);
final String mimeType = MediaFile.getMimeTypeForFile(imagePath);
if (TextUtils.isEmpty(name)) name = "Image";
final PendingParams params = new PendingParams(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, name, mimeType);
final Context context = AppGlobals.getInitialApplication();
final Uri pendingUri = createPending(context, params);
try (PendingSession session = openPending(context, pendingUri)) {
try (InputStream in = new FileInputStream(file);
OutputStream out = session.openOutputStream()) {
FileUtils.copy(in, out);
}
return session.publish().toString();
} catch (Exception e) {
Log.w(TAG, "Failed to insert image", e);
context.getContentResolver().delete(pendingUri, null, null);
return null;
}
}
新方法:
Android10后该方法不需要获得权限。
public static void putBitmapToMedia(Context context,String fileName,Bitmap bm) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
try {
OutputStream out = context.getContentResolver().openOutputStream(uri);
bm.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
ToastUtil.longToast(context, "图片保存成功!");
} catch (IOException e) {
ToastUtil.shortToast(context,"图片保存失败");
e.printStackTrace();
}
}