Android Uri url file path区别/如何在SD卡上保存一张图片呢?

Android URI&&URL的定义与使用

Android Url&Uri详细解析

Android URI简介

Android中的Uri详解

 

在操作MediaStore的时候会用到Uri。

如何在SD卡上保存一张图片呢?

(1)之前的方式

我们都是在SD卡下面建一个目录比如/storage/emulated/0/shvdownload/video/tempVideo,然后把把需要保存的媒体资源(图片、视频)通过File 输出流的方式写入文件。然后就不管了,让系统触发扫描的时候,把这个媒体信息放到MediaStore中;或者通过触发MediaStore扫描,看参考文章。

从Android10开始,引入了分区存储,不让直接通过File的方式操作SD卡路径了。必须通过MediaStore,也就是说,让MediaStore给你指定存放位置,暴露抽象的Uri,让你用,真实路径隐藏。

(2)通过MediaStore的方式

MediaStore其实就是一个数据库,里面存的是媒体信息(名字、描述、路径等),访问MediaStore通过ContentResolver。MediaStore存的只是媒体信息,保存媒体本身到本地还是需要我们自己完成的,只不过MediaStore告诉了我们位置,而且有写入的方式。

    public Uri createImageUri(Context context) {
        ContentValues values = new ContentValues();
        // 需要指定文件信息时,非必须
        values.put(MediaStore.Images.Media.DESCRIPTION, "This is an image");
        values.put(MediaStore.Images.Media.DISPLAY_NAME, "Image.png");
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
        values.put(MediaStore.Images.Media.TITLE, "Image.png");
        //values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/test");

        return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    }

先在MediaStore的Images中创建一条表示图片的记录,返回表示这个图片的Uri。

我们连续调用两次,看看结果都是啥

    public void showMediaInfo(Context context, Uri uri) {
        Cursor cursor= context.getContentResolver().query(uri, null, null, null, null);
        //System.out.println("lzy cursor.getCount() = " + cursor.getCount());
        cursor.moveToFirst();
        String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
        String DESCRIPTION = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DESCRIPTION));
        String DISPLAY_NAME = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME));
        String MIME_TYPE = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.MIME_TYPE));
        String TITLE = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE));

        System.out.println("lzy path = " + path);
        System.out.println("lzy DESCRIPTION = " + DESCRIPTION);
        System.out.println("lzy DISPLAY_NAMEDISPLAY_NAME = " + DISPLAY_NAME);
        System.out.println("lzy MIME_TYPE = " + MIME_TYPE);
        System.out.println("lzy TITLE = " + TITLE);
    }
2020-10-15 14:19:56.297 7041-7041/com.sohu.sohuvideo I/System.out: lzy uri = content://media/external/images/media/42389
2020-10-15 14:19:56.300 7041-7041/com.sohu.sohuvideo I/System.out: lzy path = /storage/emulated/0/Pictures/1602742795276.jpg
2020-10-15 14:19:56.300 7041-7041/com.sohu.sohuvideo I/System.out: lzy DESCRIPTION = This is an image
2020-10-15 14:19:56.301 7041-7041/com.sohu.sohuvideo I/System.out: lzy DISPLAY_NAMEDISPLAY_NAME = Image.png
2020-10-15 14:19:56.301 7041-7041/com.sohu.sohuvideo I/System.out: lzy MIME_TYPE = image/png
2020-10-15 14:19:56.301 7041-7041/com.sohu.sohuvideo I/System.out: lzy TITLE = Image.png
2020-10-15 14:19:57.317 7041-7041/com.sohu.sohuvideo I/System.out: lzy uri = content://media/external/images/media/42389
2020-10-15 14:19:57.343 7041-7041/com.sohu.sohuvideo I/System.out: lzy path = /storage/emulated/0/Pictures/1602742796302.jpg
2020-10-15 14:19:57.343 7041-7041/com.sohu.sohuvideo I/System.out: lzy DESCRIPTION = This is an image
2020-10-15 14:19:57.344 7041-7041/com.sohu.sohuvideo I/System.out: lzy DISPLAY_NAMEDISPLAY_NAME = Image.png
2020-10-15 14:19:57.344 7041-7041/com.sohu.sohuvideo I/System.out: lzy MIME_TYPE = image/png
2020-10-15 14:19:57.344 7041-7041/com.sohu.sohuvideo I/System.out: lzy TITLE = Image.png

看到没,有两条记录,MediaStore给指定了真正的路径是在/storage/emulated/0/Pictures/下面。

看看MediaStore.Images.Media.EXTERNAL_CONTENT_URI是啥

            /**
             * Get the content:// style URI for the image media table on the
             * given volume.
             *
             * @param volumeName the name of the volume to get the URI for
             * @return the URI to the image media table on the given volume
             */
            public static Uri getContentUri(String volumeName) {
                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
                        "/images/media");
            }

            /**
             * The content:// style URI for the internal storage.
             */
            public static final Uri INTERNAL_CONTENT_URI =
                    getContentUri("internal");

            /**
             * The content:// style URI for the "primary" external storage
             * volume.
             */
            public static final Uri EXTERNAL_CONTENT_URI =
                    getContentUri("external");

其实就是把“external”传给了getContentUri方法。

访问共享存储空间中的媒体文件官方也给了在MediaStore写入一条的例子,我们看一下

// Add a specific media item.
ContentResolver resolver = getApplicationContext()
        .getContentResolver();

// Find all audio files on the primary external storage device.
// On API <= 28, use VOLUME_EXTERNAL instead.
Uri audioCollection = MediaStore.Audio.Media.getContentUri(
        MediaStore.VOLUME_EXTERNAL_PRIMARY);

// Publish a new song.
ContentValues newSongDetails = new ContentValues();
newSongDetails.put(MediaStore.Audio.Media.DISPLAY_NAME,
        "My Song.mp3");

// Keeps a handle to the new song's URI in case we need to modify it
// later.
Uri myFavoriteSongUri = resolver
        .insert(audioCollection, newSongDetails);

这个是Audio的,和Images是一个意思。看Uri audioCollection = MediaStore.Audio.Media.getContentUri(
        MediaStore.VOLUME_EXTERNAL_PRIMARY)这句话MediaStore.VOLUME_EXTERNAL_PRIMARY和MediaStore.VOLUME_EXTERNAL是Android10(29)新加的api,分别表示external_primary和external,在之前的系统只有external,所以MediaStore.Audio.Media.getContentUri(
        MediaStore.VOLUME_EXTERNAL)和MediaStore.Audio.Media.EXTERNAL_CONTENT_URI是一个意思。

external_primary的介绍看存储卷

上面只是说了,怎么在MediaStore中插入媒体信息,没有说怎么把媒体本身保存到本地。

官方介绍了两种打开媒体文件的方法,文件描述符和文件流。

而且有文章是用文件流打开的,然后把数据写入AndroidQ(10)分区存储完美适配之下载图片(文件)本地。这种方式,应该是没有问题的,比如下载视频或者图片到本地。对于视频的迁移有没有其它办法呢?

 

 

 

 

 

 

其实通过MediaStore保存共享文件的方式Android一开始就有,“分区存储”模型要求保存共享文件必须使用MediaStore的方式,使用File直接访问路径是禁止的,会报错。

 

三种方法,刷新 Android 的 MediaStore!让你保存的图片立即出现在相册里!

Android使用MediaStore获取手机上的文件

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值