2010-05-07 115 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複製該內容。無論是臨時副本(例如,用於文件上載操作,然後刪除)還是持久副本(例如,用於應用程序的「導入」功能)都由您決定。