Android 10:通过MediaStore获取带有位置信息的图库 [英] Android 10: fetch the gallery via MediaStore with location information

查看:87
本文介绍了Android 10:通过MediaStore获取带有位置信息的图库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

查看Android 10中引入的存储访问更改在此处,默认情况下,位置信息已被删除.

Looking at the storage access changes introduced in Android 10 here, location informations are now redacted by default.

Google要求我们在"MediaStore"页面上调用 setRequireOriginal().以媒体的uri作为参数的对象.当您一张一张地获取媒体时,此方法有效,但是当我们查询整个画廊的ContentResolver时该怎么办?

Google asks us to call setRequireOriginal() on the "MediaStore" object with the media's uri as a parameter. This works when you fetch medias one by one, but what about when we query the ContentResolver for the whole gallery?

查看此示例:

String[] projection = {
        MediaStore.Files.FileColumns._ID,
        MediaStore.Files.FileColumns.DATA,
        MediaStore.Files.FileColumns.MEDIA_TYPE,
        MediaStore.Images.Media.DATE_TAKEN,
        MediaStore.Images.Media.WIDTH,
        MediaStore.Images.Media.HEIGHT,
        MediaStore.Images.Media.LATITUDE, // <----- THIS
        MediaStore.Images.Media.LONGITUDE, // <----- THIS
        MediaStore.Images.Media.MIME_TYPE,
};

String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
        + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;

Uri queryUri = MediaStore.Files.getContentUri("external");

Cursor cursor = null;
MediaStore a ;

try {
    cursor = context.getContentResolver().query(queryUri, projection, selection,
            null, MediaStore.Images.Media.DATE_TAKEN + " DESC");


}
catch (NullPointerException ex){
}

从Q开始,纬度和经度始终设置为0.如果在清单中添加了 ACCESS_MEDIA_LOCATION 权限,是否可以获取一批媒体的位置数据?

Starting Q the latitude and longitude are always set to 0. Is there a way to get the location data for a batch of medias assuming the ACCESS_MEDIA_LOCATION permission is added in the Manifest?

推荐答案

不幸的是,MediaStore.Images.Media.LATITUDE和MediaStore.Images.Media.LONGITUDE是

Unfortunately, MediaStore.Images.Media.LATITUDE and MediaStore.Images.Media.LONGITUDE were deprecated in Android Q.

解决方法像这样使用 ExifInterface :

Cursor cursor = null;
try {
    String[] projection = {
            MediaStore.Files.FileColumns._ID,
            MediaStore.Images.Media.DATE_TAKEN,
            MediaStore.Images.Media.WIDTH,
            MediaStore.Images.Media.HEIGHT,
            MediaStore.MediaColumns.TITLE,
            MediaStore.Images.Media.MIME_TYPE,
            MediaStore.Images.Media.LATITUDE,
            MediaStore.Images.Media.LONGITUDE
    };
    cursor = getContentResolver().query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            projection,
            null,
            null,
            MediaStore.Images.Media.DATE_TAKEN + " DESC");


    int idColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID);
    int titleColumn = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.TITLE);
    int latColumn = BuildCompat.isAtLeastQ() ? -1
            : cursor.getColumnIndexOrThrow(MediaStore.Images.Media.LATITUDE);
    int longColumn = BuildCompat.isAtLeastQ() ? -1
            : cursor.getColumnIndexOrThrow(MediaStore.Images.Media.LONGITUDE);
    while (cursor.moveToNext()) {

        Uri photoUri = Uri.withAppendedPath(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                cursor.getString(idColumn));
        String title = cursor.getString(titleColumn);

        final double[] latLong;
        if (BuildCompat.isAtLeastQ()) {
            photoUri = MediaStore.setRequireOriginal(photoUri);
            InputStream stream = getContentResolver().openInputStream(photoUri);
            if (stream == null) {
                Log.w(TAG, "Got a null input stream for " + photoUri);
                continue;
            }

            ExifInterface exifInterface = new ExifInterface(stream);
            double[] returnedLatLong = exifInterface.getLatLong();
            // If it returns null, fall back to {0.0, 0.0}.
            latLong = returnedLatLong != null ? returnedLatLong : new double[2];

            // After using ExifInterface, the stream should not be reused.
            stream.close();
        } else {
            latLong = new double[]{
                    cursor.getFloat(latColumn),
                    cursor.getFloat(longColumn)
            };
        }

        Log.i(TAG, title + " | lat: " + latLong[0] + " | lng: " + latLong[1]);
    }
} catch (NullPointerException | IOException ex) {
    Log.e(TAG, "Caught exception", ex);
} finally {
    if (cursor != null) {
        cursor.close();
    }
}

这是获得纬度&的唯一方法目前在Android Q上的照片经度.

This is the only way to get latitude & longitude of a photo on Android Q at the moment.

这需要持有 ACCESS_MEDIA_LOCATION 权限.注意,该许可不是用户在设置UI中可见".(),这意味着用户即使看到弹出窗口也无法获得许可它是运行时权限.这意味着您必须在运行时请求许可(与清单文件不同),但用户不必同意.在此处添加此内容是因为您可能想知道为什么没有显示额外的UI弹出窗口.

This requires holding the ACCESS_MEDIA_LOCATION permission. Note, this permission is not "user visible in the settings UI" (source), which means the user won't see a popup asking for permission, even though it is a runtime permission. This means you have to ask for permission during runtime (in contrast to just the manifest file) but the user won't have to consent to it. Adding this here because you might be wondering why no extra UI popups are shown.

这篇关于Android 10:通过MediaStore获取带有位置信息的图库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆