在奇巧(或新画廊)之前,意图。ACTION_GET_CONTENT返回一个这样的URI
内容:/ /媒体/外部/图片/媒体/ 3951。
使用ContentResolver并查询 media . data返回文件URL。
然而,在奇巧,画廊返回一个URI(通过“Last”)像这样:
内容:/ / com.android.providers.media.documents /文档/图片:3951
我该怎么处理呢?
在奇巧(或新画廊)之前,意图。ACTION_GET_CONTENT返回一个这样的URI
内容:/ /媒体/外部/图片/媒体/ 3951。
使用ContentResolver并查询 media . data返回文件URL。
然而,在奇巧,画廊返回一个URI(通过“Last”)像这样:
内容:/ / com.android.providers.media.documents /文档/图片:3951
我该怎么处理呢?
当前回答
对于这种类型的uri 内容:/ / % 3 a19298 com.android.providers.media.documents /文件/文档 或者uri.getAuthority()是这些中的任何一个
"com.google.android.apps.docs.storage".equals(uri.getAuthority()) || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
使用这个函数
private static String getDriveFilePath(Uri uri, Context context) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getCacheDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}
其他回答
Just wanted to say that this answer is brilliant and I'm using it for a long time without problems. But some time ago I've stumbled upon a problem that DownloadsProvider returns URIs in format content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf and hence app is crashed with NumberFormatException as it's impossible to parse its uri segments as long. But raw: segment contains direct uri which can be used to retrieve a referenced file. So I've fixed it by replacing isDownloadsDocument(uri) if content with following:
final String id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
try {
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
Log.e("FileUtils", "Downloads provider returned unexpected uri " + uri.toString(), e);
return null;
}
}
我相信已经发布的回复应该会让人们朝着正确的方向前进。然而,以下是我所做的对我正在更新的遗留代码有意义的事情。遗留代码使用图库中的URI来更改和保存图像。
在4.4之前(和谷歌驱动器),uri看起来是这样的: 内容:/ /媒体/外部/图片/媒体/ 41
正如问题中所述,它们通常是这样的: 内容:/ / com.android.providers.media.documents /文档/图片:3951
因为我需要保存图像的能力,而不打扰已经存在的代码,我只是从图库中复制URI到应用程序的数据文件夹中。然后从数据文件夹中保存的图像文件中产生一个新的URI。
这个想法是这样的:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent), CHOOSE_IMAGE_REQUEST);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
File tempFile = new File(this.getFilesDir().getAbsolutePath(), "temp_image");
//Copy URI contents into temporary file.
try {
tempFile.createNewFile();
copyAndClose(this.getContentResolver().openInputStream(data.getData()),new FileOutputStream(tempFile));
}
catch (IOException e) {
//Log Error
}
//Now fetch the new URI
Uri newUri = Uri.fromFile(tempFile);
/* Use new URI object just like you used to */
}
注意- copyAndClose()只是执行文件I/O,将InputStream复制到FileOutputStream。代码没有被发布。
对于那些仍然在Android SDK版本23及以上使用@Paul Burke的代码的人,如果你的项目遇到错误说你缺少EXTERNAL_PERMISSION,并且你非常确定你已经在AndroidManifest.xml文件中添加了user-permission。这是因为在Android API 23或以上和谷歌中,当您在运行时执行访问文件的操作时,有必要再次保证权限。
这意味着:如果你的SDK版本是23或以上,当你选择图片文件并想知道它的URI时,你会被要求读取和写入权限。
下面是我的代码,除了Paul Burke的解决方案。我添加这些代码,我的项目开始工作良好。
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static final String[] PERMISSINOS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSINOS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
在你的activity&fragment请求URI的地方:
private void pickPhotoFromGallery() {
CompatUtils.verifyStoragePermissions(this);
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
// startActivityForResult(intent, REQUEST_PHOTO_LIBRARY);
startActivityForResult(Intent.createChooser(intent, "选择照片"),
REQUEST_PHOTO_LIBRARY);
}
在我的例子中,CompatUtils.java是我定义verifyStoragePermissions方法的地方(作为静态类型,所以我可以在其他活动中调用它)。
此外,如果在调用verifyStoragePermissions方法之前先设置一个if状态来查看当前SDK版本是否高于23,这应该更有意义。
你的问题的答案是你需要有权限。在manifest.xml文件中输入以下代码:
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_OWNER_DATA"></uses-permission>
<uses-permission android:name="android.permission.READ_OWNER_DATA"></uses-permission>`
这对我很管用……
试试这个:
if (Build.VERSION.SDK_INT <19){
Intent intent = new Intent();
intent.setType("image/jpeg");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.select_picture)),GALLERY_INTENT_CALLED);
} else {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/jpeg");
startActivityForResult(intent, GALLERY_KITKAT_INTENT_CALLED);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != Activity.RESULT_OK) return;
if (null == data) return;
Uri originalUri = null;
if (requestCode == GALLERY_INTENT_CALLED) {
originalUri = data.getData();
} else if (requestCode == GALLERY_KITKAT_INTENT_CALLED) {
originalUri = data.getData();
final int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(originalUri, takeFlags);
}
loadSomeStreamAsynkTask(originalUri);
}
可能需要
@SuppressLint(“NewApi”)
for
takePersistableUriPermission