在真实 Android 设备上测试应用程序时 URI 无效,但在模拟器上测试时有效
Invalid URI when testing app on real Android device, but works when testing on emulator
我有一个应用程序可以提取上传图像的 GPS 坐标(通过 ExifInterface)- 为此,它必须将图像的 Uri 转换为其文件路径。它在模拟器上测试时有效(两个模拟器,不同的 Android 版本),但在真正的 Android 设备上测试时不起作用。
真实设备上的错误输出:
01-08 19:39:35.203: D/fr.free.nrw.commons.upload.ShareActivity(16980): Uri: content://media/external/images/media/10716
01-08 19:39:35.203: W/Image(16980): java.lang.IllegalArgumentException: Invalid URI: content://media/external/images/media/10716
01-08 19:39:35.203: W/Image(16980): at android.provider.DocumentsContract.getDocumentId(DocumentsContract.java:752)
01-08 19:39:35.203: W/Image(16980): at fr.free.nrw.commons.upload.FilePathConverter.getFilePath(FilePathConverter.java:31)
01-08 19:39:35.203: W/Image(16980): at fr.free.nrw.commons.upload.ShareActivity.onCreate(ShareActivity.java:193)
01-08 19:39:35.203: W/Image(16980): at android.app.Activity.performCreate(Activity.java:6289)
01-08 19:39:35.203: W/Image(16980): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2655)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2767)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread.access0(ActivityThread.java:177)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
01-08 19:39:35.203: W/Image(16980): at android.os.Handler.dispatchMessage(Handler.java:102)
01-08 19:39:35.203: W/Image(16980): at android.os.Looper.loop(Looper.java:145)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread.main(ActivityThread.java:5951)
01-08 19:39:35.203: W/Image(16980): at java.lang.reflect.Method.invoke(Native Method)
01-08 19:39:35.203: W/Image(16980): at java.lang.reflect.Method.invoke(Method.java:372)
01-08 19:39:35.203: W/Image(16980): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
01-08 19:39:35.203: W/Image(16980): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
ShareActivity中调用FilePathConverter的相关代码:
mediaUriString = mediaUri.toString();
Log.d(TAG, "Uri: " + mediaUriString);
//convert image Uri to file path
FilePathConverter uriObj = new FilePathConverter(this, mediaUri);
String filePath = uriObj.getFilePath();
将图像 Uri 转换为文件路径的 FilePathCoverter 代码:
public class FilePathConverter {
private Uri uri;
private Context context;
public FilePathConverter(Context context, Uri uri) {
this.context = context;
this.uri = uri;
}
public String getFilePath(){
String filePath ="";
try {
// Will return "image:x*"
String wholeID = DocumentsContract.getDocumentId(uri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = {MediaStore.Images.Media.DATA};
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
Log.d("Image", "File path: " + filePath);
return filePath;
} catch (IllegalArgumentException e) {
Log.w("Image", e);
return null;
}
}
}
整个代码库可以在 GitHub if needed. The closest answer I can find is How to use ExifInterface with a stream or URI 上找到,但它也不起作用。
我的模拟器输出:
01-08 08:11:48.421: D/fr.free.nrw.commons.upload.ShareActivity(2188): Uri: content://com.android.providers.media.documents/document/image%3A24
01-08 08:11:48.421: D/fr.free.nrw.commons.upload.ShareActivity(2188): Ext storage dir: /storage/sdcard
01-08 08:11:48.429: D/fr.free.nrw.commons.upload.ShareActivity(2188): Filepath: /storage/sdcard/Download/20151231_234740.jpg
01-08 08:11:48.429: D/fr.free.nrw.commons.upload.ShareActivity(2188): Calling GPSExtractor
01-08 08:11:48.436: D/fr.free.nrw.commons.upload.ShareActivity(2188): Decimal coords of image: -36.85254286111111|174.7669525
真实设备上的输出:
01-08 21:07:59.558: D/fr.free.nrw.commons.upload.ShareActivity(30904): Uri: content://media/external/images/media/10777
01-08 21:07:59.558: D/fr.free.nrw.commons.upload.ShareActivity(30904): Ext storage dir: /storage/emulated/0
试试这个,
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.INTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
因为你的模拟器不能有sdcard
供参考。
How to get my Android device Internal Download Folder path
如果您想从 uri 获取真实路径,请使用此方法。
private String getRealPathFromURI(Uri contentURI) {
String result;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx);
cursor.close();
}
return result;
}
我有一个应用程序可以提取上传图像的 GPS 坐标(通过 ExifInterface)- 为此,它必须将图像的 Uri 转换为其文件路径。它在模拟器上测试时有效(两个模拟器,不同的 Android 版本),但在真正的 Android 设备上测试时不起作用。
真实设备上的错误输出:
01-08 19:39:35.203: D/fr.free.nrw.commons.upload.ShareActivity(16980): Uri: content://media/external/images/media/10716
01-08 19:39:35.203: W/Image(16980): java.lang.IllegalArgumentException: Invalid URI: content://media/external/images/media/10716
01-08 19:39:35.203: W/Image(16980): at android.provider.DocumentsContract.getDocumentId(DocumentsContract.java:752)
01-08 19:39:35.203: W/Image(16980): at fr.free.nrw.commons.upload.FilePathConverter.getFilePath(FilePathConverter.java:31)
01-08 19:39:35.203: W/Image(16980): at fr.free.nrw.commons.upload.ShareActivity.onCreate(ShareActivity.java:193)
01-08 19:39:35.203: W/Image(16980): at android.app.Activity.performCreate(Activity.java:6289)
01-08 19:39:35.203: W/Image(16980): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2655)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2767)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread.access0(ActivityThread.java:177)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
01-08 19:39:35.203: W/Image(16980): at android.os.Handler.dispatchMessage(Handler.java:102)
01-08 19:39:35.203: W/Image(16980): at android.os.Looper.loop(Looper.java:145)
01-08 19:39:35.203: W/Image(16980): at android.app.ActivityThread.main(ActivityThread.java:5951)
01-08 19:39:35.203: W/Image(16980): at java.lang.reflect.Method.invoke(Native Method)
01-08 19:39:35.203: W/Image(16980): at java.lang.reflect.Method.invoke(Method.java:372)
01-08 19:39:35.203: W/Image(16980): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
01-08 19:39:35.203: W/Image(16980): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
ShareActivity中调用FilePathConverter的相关代码:
mediaUriString = mediaUri.toString();
Log.d(TAG, "Uri: " + mediaUriString);
//convert image Uri to file path
FilePathConverter uriObj = new FilePathConverter(this, mediaUri);
String filePath = uriObj.getFilePath();
将图像 Uri 转换为文件路径的 FilePathCoverter 代码:
public class FilePathConverter {
private Uri uri;
private Context context;
public FilePathConverter(Context context, Uri uri) {
this.context = context;
this.uri = uri;
}
public String getFilePath(){
String filePath ="";
try {
// Will return "image:x*"
String wholeID = DocumentsContract.getDocumentId(uri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = {MediaStore.Images.Media.DATA};
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
Log.d("Image", "File path: " + filePath);
return filePath;
} catch (IllegalArgumentException e) {
Log.w("Image", e);
return null;
}
}
}
整个代码库可以在 GitHub if needed. The closest answer I can find is How to use ExifInterface with a stream or URI 上找到,但它也不起作用。
我的模拟器输出:
01-08 08:11:48.421: D/fr.free.nrw.commons.upload.ShareActivity(2188): Uri: content://com.android.providers.media.documents/document/image%3A24
01-08 08:11:48.421: D/fr.free.nrw.commons.upload.ShareActivity(2188): Ext storage dir: /storage/sdcard
01-08 08:11:48.429: D/fr.free.nrw.commons.upload.ShareActivity(2188): Filepath: /storage/sdcard/Download/20151231_234740.jpg
01-08 08:11:48.429: D/fr.free.nrw.commons.upload.ShareActivity(2188): Calling GPSExtractor
01-08 08:11:48.436: D/fr.free.nrw.commons.upload.ShareActivity(2188): Decimal coords of image: -36.85254286111111|174.7669525
真实设备上的输出:
01-08 21:07:59.558: D/fr.free.nrw.commons.upload.ShareActivity(30904): Uri: content://media/external/images/media/10777
01-08 21:07:59.558: D/fr.free.nrw.commons.upload.ShareActivity(30904): Ext storage dir: /storage/emulated/0
试试这个,
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.INTERNAL_CONTENT_URI,
column, sel, new String[]{id}, null);
因为你的模拟器不能有sdcard
供参考。 How to get my Android device Internal Download Folder path
如果您想从 uri 获取真实路径,请使用此方法。
private String getRealPathFromURI(Uri contentURI) {
String result;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) { // Source is Dropbox or other similar local file path
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx);
cursor.close();
}
return result;
}