2010-05-07 147 views
73

我试图从库中获取图像。android获取Uri.getPath的实际路径()

Intent intent = new Intent(); 
intent.setType("image/*"); 
intent.setAction(Intent.ACTION_GET_CONTENT); 
startActivityForResult(Intent.createChooser(intent, "Select picture"), resultCode); 

当我从这个活动返回后,我有一个数据,其中包含Uri。它看起来像:

content://media/external/images/1 

我怎么能转换这个路径真正的(就像“/sdcard/image.png”)?

谢谢

+1

这显然是一个非常晚的评论,但我只是想指出的是,startActivityForResultCode方法将请求代码作为参数,而不是结果代码。 – 2015-04-08 22:17:09

+0

做了'uri.getPath()'没有给你真正的路径吗? – Darpan 2015-07-09 05:49:23

回答

47

真的有必要让你得到一条物理路径吗?
例如,ImageView.setImageURI()ContentResolver.openInputStream()允许您在不知道其真实路径的情况下访问文件的内容。

+0

正是我所期待的,但无法找到。谢谢。 – davs 2010-05-07 19:04:45

+3

对不起,如果我想将这个图像转换为文件,没有得到真正的路径如何做到这一点? – Chlebta 2014-11-24 10:44:38

+3

物理路径可以访问文件名和扩展名。在文件上传的情况下。 – Clocker 2015-11-11 03:52:17

165

这是我做的:

Uri selectedImageURI = data.getData(); 
imageFile = new File(getRealPathFromURI(selectedImageURI)); 

和:

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; 
} 

注:​​方法已过时,所以我不使用它。

Last edit:改进。我们应该关闭光标!

+0

非常感谢这一点 - 我在下面的回答中做了一个小小的更新。如果你编辑你的,我会删除我的。 – 2013-06-03 17:58:31

+0

@ChrisR完成!也谢谢你! – cesards 2013-06-03 21:09:40

+1

http://stackoverflow.com/a/7265235/375093这是另一种选择,但建议比以上更好。检查出来 – Sundeep 2013-07-19 20:48:16

14

@Rene Juuse - 上面的评论...感谢您的链接!

。 获取真实路径的代码与一个SDK有点不同,因此下面我们介绍了三种处理不同SDK的方法。

getRealPathFromURI_API19():返回(或以上但没有测试)API 19 getRealPathFromURI_API11to18()实际路径:用于API 11返回到API 18 getRealPathFromURI_below11()实际路径:返回低于11为API真实路径

public class RealPathUtil { 

@SuppressLint("NewApi") 
public static String getRealPathFromURI_API19(Context context, Uri uri){ 
    String filePath = ""; 
    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(); 
    return filePath; 
} 


@SuppressLint("NewApi") 
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) { 
     String[] proj = { MediaStore.Images.Media.DATA }; 
     String result = null; 

     CursorLoader cursorLoader = new CursorLoader(
       context, 
     contentUri, proj, null, null, null);   
     Cursor cursor = cursorLoader.loadInBackground(); 

     if(cursor != null){ 
     int column_index = 
     cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
     cursor.moveToFirst(); 
     result = cursor.getString(column_index); 
     } 
     return result; 
} 

public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){ 
      String[] proj = { MediaStore.Images.Media.DATA }; 
      Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null); 
      int column_index 
     = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
      cursor.moveToFirst(); 
      return cursor.getString(column_index); 
} 

字体:http://hmkcode.com/android-display-selected-image-and-its-real-path/


UPDATE 201 3月6日

要解决图像路径的所有问题,我尝试创建一个自定义图库作为Facebook和其他应用程序。这是因为你只能使用本地文件(真实文件,不是虚拟文件或临时文件),所以我解决了这个库的所有问题。

https://github.com/nohana/Laevatein(该库是拍摄照片从相机或galery选择,如果你从图库中选择,他与唱片抽屉里只显示本地文件)

+1

API> = 19没有在LG G3上运行5.1 – Clocker 2015-11-11 04:04:40

+0

@Clocker在三星S4上既没有 – Ricardo 2015-12-07 23:30:09

+0

我真的很难在android中管理所有类型的源图像。如果你上传,或者从Galery选择,最好的解决方案是从Facebook创建一个Galery。它是一个自定义画廊,只有设备中的实际图像,没有虚拟或临时的。我使用这个库修复了我的应用中的所有问题。 https://github.com/nohana/Laevatein它非常好的图书馆。定制并不简单,但您可以打开代码并进行更改。我希望这可以帮助你。 – luizfelipetx 2016-03-25 05:15:54

10

注意这是@user3516549 answer的改进,我用Android 6.0.1检查了Moto G3
我有这个问题,所以我尝试了@ user3516549的答案,但是在某些情况下它不能正常工作。 我发现在Android 6中。0(或以上)当我们开始图库摄像意图,然后屏幕会打开,显示最近的图像时,从该列表中的用户选择图像,我们将得到URI作为

content://com.android.providers.media.documents/document/image%3A52530 

而如果滑动抽屉,而不是用户选择图库最近那么我们将得到URI作为

content://media/external/images/media/52530 

所以我必须处理它在getRealPathFromURI_API19()

public static String getRealPathFromURI_API19(Context context, Uri uri) { 
     String filePath = ""; 
     if (uri.getHost().contains("com.android.providers.media")) { 
      // Image pick from recent 
      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(); 
      return filePath; 
     } else { 
      // image pick from gallery 
      return getRealPathFromURI_BelowAPI11(context,uri) 
     } 

    } 

编辑:,如果你想获得在更高版本外部SD卡文件的图像路径,然后检查my question

+0

嗨,朋友,是的,这是真的。但是,这是因为现在谷歌有一个默认的格式,将手机上的所有照片上传到谷歌文档。只需将thumbinal保存在手机中。如果您从Google文档中获得此uri,则在使用此文件之前,您需要下载照片。 这一般不好。所以,要解决所有问题,现在即时通讯使用这个库。 (这个库只是使用本地文件,通过这个解决方案你的问题将得到解决),或者你可以从库中提取代码并改进自己来解决你的问题。 https://github.com/nohana/Laevatein 我希望这可以帮助你。 – luizfelipetx 2016-05-12 12:48:57

+0

1+,它的工作非常适合我。正如@JaiprakasSoni在他的回答中所说的那样,当我在Moto G4游戏中运行我的应用时,我遇到了同样的问题,但是当我使用上面的代码时,它对我来说工作正常。谢谢。你节省了我的时间 – Shailesh 2017-03-23 11:17:03

+0

这个工作对我来说棉花糖6.0 – androidXP 2017-10-22 11:34:26

1

斐伊川这里是我从相机或galeery

//我的变量声明摄像图像的完整代码

protected static final int CAMERA_REQUEST = 0; 
    protected static final int GALLERY_REQUEST = 1; 
    Bitmap bitmap; 
    Uri uri; 
    Intent picIntent = null; 

// ONCLICK

if (v.getId()==R.id.image_id){ 
      startDilog(); 
     } 

//方法主体

private void startDilog() { 
    AlertDialog.Builder myAlertDilog = new AlertDialog.Builder(yourActivity.this); 
    myAlertDilog.setTitle("Upload picture option.."); 
    myAlertDilog.setMessage("Where to upload picture????"); 
    myAlertDilog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      picIntent = new Intent(Intent.ACTION_GET_CONTENT,null); 
      picIntent.setType("image/*"); 
      picIntent.putExtra("return_data",true); 
      startActivityForResult(picIntent,GALLERY_REQUEST); 
     } 
    }); 
    myAlertDilog.setNegativeButton("Camera", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
      startActivityForResult(picIntent,CAMERA_REQUEST); 
     } 
    }); 
    myAlertDilog.show(); 
} 

//与物联网

休息
@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 
    if (requestCode==GALLERY_REQUEST){ 
     if (resultCode==RESULT_OK){ 
      if (data!=null) { 
       uri = data.getData(); 
       BitmapFactory.Options options = new BitmapFactory.Options(); 
       options.inJustDecodeBounds = true; 
       try { 
        BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options); 
        options.inSampleSize = calculateInSampleSize(options, 100, 100); 
        options.inJustDecodeBounds = false; 
        Bitmap image = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options); 
        imageofpic.setImageBitmap(image); 
       } catch (FileNotFoundException e) { 
        e.printStackTrace(); 
       } 
      }else { 
       Toast.makeText(getApplicationContext(), "Cancelled", 
         Toast.LENGTH_SHORT).show(); 
      } 
     }else if (resultCode == RESULT_CANCELED) { 
      Toast.makeText(getApplicationContext(), "Cancelled", 
        Toast.LENGTH_SHORT).show(); 
     } 
    }else if (requestCode == CAMERA_REQUEST) { 
     if (resultCode == RESULT_OK) { 
      if (data.hasExtra("data")) { 
       bitmap = (Bitmap) data.getExtras().get("data"); 
       uri = getImageUri(YourActivity.this,bitmap); 
       File finalFile = new File(getRealPathFromUri(uri)); 
       imageofpic.setImageBitmap(bitmap); 
      } else if (data.getExtras() == null) { 

       Toast.makeText(getApplicationContext(), 
         "No extras to retrieve!", Toast.LENGTH_SHORT) 
         .show(); 

       BitmapDrawable thumbnail = new BitmapDrawable(
         getResources(), data.getData().getPath()); 
       pet_pic.setImageDrawable(thumbnail); 

      } 

     } else if (resultCode == RESULT_CANCELED) { 
      Toast.makeText(getApplicationContext(), "Cancelled", 
        Toast.LENGTH_SHORT).show(); 
     } 
    } 
} 

private String getRealPathFromUri(Uri tempUri) { 
    Cursor cursor = null; 
    try { 
     String[] proj = { MediaStore.Images.Media.DATA }; 
     cursor = this.getContentResolver().query(tempUri, proj, null, null, null); 
     int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
     cursor.moveToFirst(); 
     return cursor.getString(column_index); 
    } finally { 
     if (cursor != null) { 
      cursor.close(); 
     } 
    } 
} 
public static int calculateInSampleSize(
     BitmapFactory.Options options, int reqWidth, int reqHeight) { 
    // Raw height and width of image 
    final int height = options.outHeight; 
    final int width = options.outWidth; 
    int inSampleSize = 1; 

    if (height > reqHeight || width > reqWidth) { 

     final int halfHeight = height/2; 
     final int halfWidth = width/2; 

     // Calculate the largest inSampleSize value that is a power of 2 and keeps both 
     // height and width larger than the requested height and width. 
     while ((halfHeight/inSampleSize) > reqHeight 
       && (halfWidth/inSampleSize) > reqWidth) { 
      inSampleSize *= 2; 
     } 
    } 
    return inSampleSize; 
} 

private Uri getImageUri(YourActivity youractivity, Bitmap bitmap) { 
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream); 
    String path = MediaStore.Images.Media.insertImage(youractivity.getContentResolver(), bitmap, "Title", null); 
    return Uri.parse(path); 
} 
+0

你如何知道这是100行'options.inSampleSize = calculateInSampleSize(options,100,100);' – 2017-01-11 09:22:47

5

编辑: 使用该解决方案在这里:https://stackoverflow.com/a/20559175/2033223 运行完美!

首先,感谢您的解决方案@luizfelipetx

我改变您的解决方案一点点。这个工作对我来说:

public static String getRealPathFromDocumentUri(Context context, Uri uri){ 
    String filePath = ""; 

    Pattern p = Pattern.compile("(\\d+)$"); 
    Matcher m = p.matcher(uri.toString()); 
    if (!m.find()) { 
     Log.e(ImageConverter.class.getSimpleName(), "ID for requested image not found: " + uri.toString()); 
     return filePath; 
    } 
    String imgId = m.group(); 

    String[] column = { MediaStore.Images.Media.DATA }; 
    String sel = MediaStore.Images.Media._ID + "=?"; 

    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
      column, sel, new String[]{ imgId }, null); 

    int columnIndex = cursor.getColumnIndex(column[0]); 

    if (cursor.moveToFirst()) { 
     filePath = cursor.getString(columnIndex); 
    } 
    cursor.close(); 

    return filePath; 
} 

注:因此,我们得到的文档和图像,这取决于,如果图片来自于“最近通话”,“画廊”或什么都。所以我在提取图像ID之前先查看它。

4

作为实际编程人员知道,没有真正的路径

A Uricontent方案是对某些内容的不透明句柄。如果Uri表示可打开的内容,则可以使用ContentResolveropenInputStream()获取该内容的InputStream。同样,Urihttphttps方案不代表本地文件,您需要使用HTTP客户端API来访问它。

只有Urifile模式标识文件(禁止在创建Uri后文件被移动或删除的情况)。

什么愚蠢的人试图通过尝试解码Uri的内容来获得文件系统路径,可能还需要使用施放法术来调用$EVIL_DEITY。在最好的情况,这将是不可靠的,原因有三:

  1. Uri值进行解码的规则可以随着时间而改变,如与Android版本发布,为Uri的结构代表一个实现细节,不接口

  2. 即使你得到一个文件系统路径,您可能没有权限访问该文件

  3. 并非所有Uri值可以通过固定的算法,因为许多应用都有自己的供应商,以及那些被解码可poi NT一切从资产BLOB列数据需要从互联网上

与任何常识没有开发商去沿着这条路进行流式传输。

如果您的API有一些需要文件的API,请使用openInputStream()中的InputStream复制该内容。无论是临时副本(例如,用于文件上载操作,然后删除)还是持久副本(例如,用于应用程序的“导入”功能)都由您决定。