Android—内部存储与外部存储、保存图片到相册

内部存储:

当一个应用卸载之后,内部存储中的这些文件也被删除。在创建内部存储文件的时候将文件属性设置成可读,其他app能够访问自己应用的数据,前提是他知道你这个应用的包名,如果一个文件的属性是私有(private),那么即使知道包名其他应用也无法访问。 内部存储空间十分有限,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。Shared Preferences和SQLite数据库都是存储在内部存储空间上的。内部存储一般用Context来获取和操作。 

内部存储的统一路径:/data/user/0/"包名(如:com.example.myapplication)"

获得内部存储路径的方式:

外部存储:

外部存储可能是手机外置的SD卡,不过现在大多数手机后盖都不可能让你轻易拆开的,因为外部存储厂商已经帮配置好了,128G、64G,大部分的容量都是外部存储。

外部存储我们可以在文件管理中,Android/data/包名中找到,而内部存储我们是看不到的。

获得外部存储路径的方式:

Android10分区存储:

在Android Q中引入了分区储存功能,在外部存储设备中为每个应用提供了一个“隔离存储沙盒”。其他应用无法直接访问应用的沙盒文件。由于文件是应用的私有文件,不再需要任何权限即可访问和保存自己的文件。此变更并有助于减少应用所需的权限数量,同时保证用户文件的隐私性。

访问自己APP目录下的文件:

  • 私有目录:内部存储+外部存储:访问不需要权限。
  • 共有目录:MediaStore,Android10以下访问需要权限,Android10后仅当访问其他应用的文件时需要权限。

文件存储在应用私有目录下,在卸载该应用后,系统会清除该应用的目录中的所有文件。有时我们要在卸载后保留这些文件,请将其保存到 MediaStore 中的某个目录下。

访问其他应用创建的文件

只有在满足以下两个条件时,您的应用才能访问其他应用创建的文件:

  1. 您的应用已获得 READ_EXTERNAL_STORAGE 权限。
  2. 这些文件位于以下其中一个明确定义的媒体集合中:
    1. 照片:存储在 MediaStore.Images 中。
    2. 视频:存储在 MediaStore.Video 中。
    3. 音乐文件:存储在 MediaStore.Audio 中。
    4. 任何其他文件(包括“downloads”目录下的文件),必须使用存储访问框架

将图片保存到外部存储:

    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();
        }
    }

 

你可能感兴趣的:(Android)