这里已经讨论了很多问题,主要是不同的结果,并且由于API的变化和不同类型的URI,没有明确的答案.
我自己没有答案,但让我们谈谈它.该ExifInterface
有一个接受一个构造函数filePath
.这本身很烦人,因为现在不鼓励依赖路径 - 你应该使用Uri
s和ContentResolver
.好.
我们的Uri
名字uri
可以从意图中检索出来onActivityResult
(如果您从图库中选择图片ACTION_GET_CONTENT
)或者可以是Uri
我们之前拥有的(如果您从相机中选择图片并打电话intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
).
我们uri
可以有两种不同的模式:
来自相机的Uris大多都有file://
架构.那些很容易治疗,因为他们坚持这条道路.你可以打电话new ExifInterface(uri.getPath())
,你就完成了.
来自画廊或其他内容提供商的Uris通常都有一个content://
界面.我个人不知道那是什么,但让我发疯.
据我所知,第二种情况应该用ContentResolver
你能得到的东西来对待Context.getContentResolver()
.以下适用于我测试的所有应用程序,无论如何:
public static ExifInterface getPictureData(Context context, Uri uri) { String[] uriParts = uri.toString().split(":"); String path = null; if (uriParts[0].equals("content")) { // we can use ContentResolver. // let’s query the DATA column which holds the path String col = MediaStore.Images.ImageColumns.DATA; Cursor c = context.getContentResolver().query(uri, new String[]{col}, null, null, null); if (c != null && c.moveToFirst()) { path = c.getString(c.getColumnIndex(col)); c.close(); return new ExifInterface(path); } } else if (uriParts[0].equals("file")) { // it's easy to get the path path = uri.getEncodedPath(); return new ExifInterface(path); } return null; }
我的问题来自Kitkat以及content://
URI.Kitkat介绍了Storage Access Framework
(见这里)以及一个新的意图ACTION_OPEN_DOCUMENT
和平台选择器.但是,有人说
在Android 4.4及更高版本中,您还可以选择使用ACTION_OPEN_DOCUMENT意图,该意图显示由系统控制的选择器UI,允许用户浏览其他应用程序可用的所有文件.通过此单一UI,用户可以从任何支持的应用程序中选择文件.
ACTION_OPEN_DOCUMENT不能替代ACTION_GET_CONTENT.您应该使用的那个取决于您的应用程序的需求.
所以为了保持这个非常简单,让我们说我们对旧版本没问题ACTION_GET_CONTENT
:它会触发一个选择器对话框,您可以在其中选择一个图库应用程序.
但是,内容方法不再适用.有时,它适用于奇巧,但永远不会奏效的棒棒糖,例如.我不知道究竟发生了什么变化.
我已经搜索并尝试过很多次; Kitkat采取的另一种方法是:
String wholeId = DocumentsContract.getDocumentId(uri); String[] parts = wholeId.split(“:”); String numberId = parts[1]; Cursor c = context.getContentResolver().query( // why external and not internal ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{ col }, MediaStore.Images.Media._ID + “=?”, new String[]{ numberId }, null);
这有时会起作用,但有些则没有.具体来说,它可以在wholeId
什么时候起作用image:2839
,但是当wholeId
它只是一个数字时显然会中断.
您可以使用系统选择器尝试此操作(即启动画廊ACTION_OPEN_DOCUMENT
):如果您从"最近"中选择一个图像,它可以工作; 如果您从"下载"中选择图像,则会中断.
直接答案是你没有,你没有在较新版本的操作系统中找到内容uris的文件路径.可以说并非所有内容都指向图片甚至文件.
这对我来说完全没问题,起初我努力避免这种情况.但是,如果我们不应该使用路径,我们应该如何使用ExifInterface类?
我不明白现代应用程序如何做到这一点 - 找到方向和元数据是您立即面临的问题,并且ContentResolver
在这个意义上不提供任何API.你有ContentResolver.openFileDescriptor()
和类似的东西,但没有API来读取元数据(真正在该文件中).可能有外部库Exif
从流中读取内容,但我想知道解决此问题的通用/平台方法.
我在谷歌的开源应用程序中搜索了类似的代码,但一无所获.
使用一些示例代码扩展alex.dorokhov的答案.支持库是一个很好的方法.
的build.gradle
dependencies { ... compile "com.android.support:exifinterface:25.0.1" ... }
示例代码:
import android.support.media.ExifInterface; ... try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) { ExifInterface exif = new ExifInterface(inputStream); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); } catch (IOException e) { e.printStackTrace(); }
一旦我们开始瞄准api 25(也许24 +上也有问题)但仍支持回到api 19,我必须这样做,因为在Android 7我们的应用程序会崩溃,如果我将URI传递给相机只是引用一个文件.因此我必须创建一个URI来传递给相机意图.
FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileprovider", tempFile);
问题是该文件无法将URI转换为真正的文件路径(除了保留临时文件路径).
现在,支持库中提供了从内容URI(实际上是一个InputStream)获取EXIF.请参阅:https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html
以下适用于我测试的所有应用程序,无论如何:
只有Uri
恰好是来自的东西才会有效MediaStore
.如果Uri
碰巧来自其他任何事情,它将失败.
直接答案是你没有,你没有在较新版本的操作系统中找到内容uris的文件路径.可以说并非所有内容都指向图片甚至文件.
正确.我已经多次指出这一点,比如这里.
如果我们不应该使用路径,我们应该如何使用ExifInterface类?
你没有.使用其他代码获取EXIF标头.
可能有外部库从流中读取Exif内容,但我想知道解决此问题的通用/平台方法.
使用外部库.
我在谷歌的开源应用程序中搜索了类似的代码,但一无所获.
你会在Mms应用程序中找到一些.