android รับเส้นทางจริงโดย Uri.getPath ()


109

ฉันพยายามดึงภาพจากแกลเลอรี

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 ใช้รหัสคำขอเป็นอาร์กิวเมนต์ไม่ใช่รหัสผลลัพธ์
Tianxiang Xiong

ไม่uri.getPath()ได้ให้เส้นทางที่แท้จริงแก่คุณ?
Darpan

# ลองยังนี้ถ้าคุณได้รับปัญหาเพื่อให้ได้เส้นทางจริงคุณสามารถลองคำตอบของฉัน คำตอบข้างต้นไม่ได้ช่วยฉัน คำอธิบาย : - วิธีนี้ได้รับ URI จากนั้นตรวจสอบระดับ API ของอุปกรณ์ Android ของคุณหลังจากนั้นตามระดับ API มันจะสร้างเส้นทางจริง รหัสสำหรับสร้างเส้นทางจริงแตกต่างกันไปตามระดับ API นี่คือคำตอบของฉัน
Sunil

คำตอบ:


56

จำเป็นจริง ๆ ที่คุณจะต้องได้รับวิถีทางกายภาพ?
ตัวอย่างเช่นImageView.setImageURI()และContentResolver.openInputStream()อนุญาตให้คุณเข้าถึงเนื้อหาของไฟล์โดยไม่ทราบเส้นทางที่แท้จริง


นั่นคือสิ่งที่ฉันมองหา แต่ไม่พบ ขอบคุณ.
davs

7
ขออภัยหากต้องการแปลงภาพนี้เป็นไฟล์โดยไม่ได้รับเส้นทางจริงจะทำอย่างไร?
Chlebta

7
พา ธ ฟิสิคัลให้การเข้าถึงชื่อไฟล์และนามสกุล ในกรณีที่อัพโหลดไฟล์
Clocker

196

นี่คือสิ่งที่ฉันทำ:

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

หมายเหตุ: managedQuery()วิธีนี้เลิกใช้แล้วดังนั้นฉันจึงไม่ได้ใช้มัน

แก้ไขล่าสุด: ปรับปรุง เราควรปิดเคอร์เซอร์ !!


1
stackoverflow.com/a/7265235/375093นี่เป็นอีกทางเลือกหนึ่ง แต่แนะนำว่าดีกว่าด้านบน ลองดูด้วยนะ
อาทิตย์

6
สวัสดี @ m3n0R ใน Moto G, MediaStore.Images.ImageColumns.DATA ไม่มีคอลัมน์เลย จะรับภาพโดยไม่มีคอลัมน์นี้ได้อย่างไร?
seema

16
ข้อผิดพลาด ตรวจสอบให้แน่ใจว่าเคอร์เซอร์เริ่มต้นอย่างถูกต้องก่อนที่จะเข้าถึงข้อมูลจากมัน .. ตรวจสอบใน API 19
Mayur R. Amipara

1
@ReneJuuse: ทรัพยากรที่ยอดเยี่ยม ในที่สุดฉันก็สามารถแก้ไขปัญหานี้ได้ด้วยเหตุนี้ - ฉันไม่รู้ว่ามีการเปลี่ยนแปลงมากมายตั้งแต่เริ่มใช้ Android ฉันใช้ API 21 และเมื่อฉันใช้การใช้งาน API 19 ที่แสดงบนไซต์ที่คุณเชื่อมโยงในที่สุดก็ใช้งานได้
Milos Ivanovic

2
ไม่สามารถอ่านแถว 0, col -1 จาก CursorWindow ตรวจสอบให้แน่ใจว่าเคอร์เซอร์เริ่มต้นอย่างถูกต้องก่อนเข้าถึงข้อมูลจากเคอร์เซอร์
Maveňツ

18

@Rene Juuse - ด้านบนในความคิดเห็น ... ขอบคุณสำหรับลิงค์นี้!

. รหัสเพื่อรับเส้นทางจริงนั้นแตกต่างจาก SDK หนึ่งไปยังอีกไฟล์หนึ่งเล็กน้อยดังนั้นด้านล่างเรามีสามวิธีที่เกี่ยวข้องกับ SDK ที่แตกต่างกัน

getRealPathFromURI_API19 (): ส่งคืนเส้นทางจริงสำหรับ API 19 (หรือสูงกว่า แต่ไม่ได้ทดสอบ) getRealPathFromURI_API11to18 (): ส่งคืนเส้นทางจริงสำหรับ API 11 ถึง API 18 getRealPathFromURI_below11 (): ส่งคืนเส้นทางจริงสำหรับ API ที่ต่ำกว่า 11

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/


อัพเดท 2559 มีนาคม

เพื่อแก้ไขปัญหาทั้งหมดเกี่ยวกับเส้นทางของภาพฉันลองสร้างแกลเลอรีที่กำหนดเองเป็น Facebook และแอพอื่น ๆ เนื่องจากคุณสามารถใช้เฉพาะไฟล์ในเครื่อง (ไฟล์จริงไม่ใช่เสมือนหรือชั่วคราว) ฉันจึงแก้ปัญหาทั้งหมดด้วยไลบรารีนี้

https://github.com/nohana/Laevatein (ไลบรารีนี้สำหรับถ่ายภาพจากกล้องหรือเลือกจากแกลเลอรี่หากคุณเลือกจากแกลเลอรีเขามีลิ้นชักพร้อมอัลบั้มและแสดงไฟล์ในเครื่องเท่านั้น)


@Clocker บน Samsung S4 ไม่ใช่
Ricardo

ฉันเป็นเรื่องยากที่จะจัดการภาพต้นฉบับทุกประเภทใน Android หากคุณอัปโหลดหรือเลือกจาก galery ทางออกที่ดีที่สุดคือสร้างเป็น galery จาก facebook เป็นแกลเลอรีที่กำหนดเองพร้อมภาพจริงในอุปกรณ์ไม่มีเสมือนหรือชั่วคราว ฉันแก้ไขปัญหาทั้งหมดในแอปของฉันโดยใช้ไลบรารีนี้ github.com/nohana/Laevatein ห้องสมุดที่ดีจริงๆ การปรับแต่งนั้นไม่ใช่เรื่องง่าย แต่คุณสามารถเปิดโค้ดและทำการเปลี่ยนแปลงได้ ฉันหวังว่านี่จะช่วยคุณได้
luizfelipetx

เสียใน Samsung S2 ของฉันด้วย 4.4.1
Oliver Dixon

ฉันต้องการรับไฟล์เช่น pdf หรือ doc ฉันไม่สามารถรับเส้นทางได้ คุณช่วยฉันได้ไหม?
Anish Kumar

1
สุดยอด! ในที่สุดสิ่งที่ได้ผลจริง กำลังมองหาสิ่งนี้มาเป็นเวลานาน ขอบคุณ.
Javatar

14

หมายเหตุนี่เป็นการปรับปรุงในคำตอบของ @ user3516549และฉันได้ตรวจสอบแล้วบน Moto G3 ด้วย Android 6.0.1
ฉันมีปัญหานี้ดังนั้นฉันจึงลองตอบ @ 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)
        }

    }

แก้ไข:หากคุณกำลังพยายามรับเส้นทางรูปภาพของไฟล์ใน sdcard ภายนอกในเวอร์ชันที่สูงกว่าให้ตรวจสอบคำถามของฉัน


สวัสดีเพื่อนใช่นั่นเป็นความจริง แต่สิ่งนี้เกิดขึ้นเนื่องจากตอนนี้ Google มีรูปแบบเริ่มต้นในการอัปโหลดรูปภาพทั้งหมดจากโทรศัพท์ของคุณไปยัง Google เอกสาร และบันทึกนิ้วหัวแม่มือในโทรศัพท์ของคุณ หากคุณได้รับ uri นี้จาก Google เอกสารคุณต้องดาวน์โหลดรูปภาพก่อนจึงจะใช้งานได้ สิ่งนี้ไม่ดีโดยทั่วไป ดังนั้นเพื่อแก้ไขปัญหาทั้งหมดที่นี่ตอนนี้ฉันใช้ไลบรารีนี้ (ไลบรารีนี้ใช้เฉพาะไฟล์ในเครื่องและด้วยวิธีนี้ปัญหาของคุณจะได้รับการแก้ไข) หรือคุณสามารถแยกโค้ดออกจากไลบรารีและปรับปรุงตัวเองเพื่อแก้ไขปัญหาของคุณ github.com/nohana/Laevateinฉันหวังว่านี่จะช่วยคุณได้
luizfelipetx

1+ มันทำงานได้สมบูรณ์แบบสำหรับฉัน ดังที่ @JaiprakasSoni กล่าวในคำตอบของเขาว่าฉันประสบปัญหาเดียวกันเมื่อฉันเรียกใช้แอพของฉันในการเล่น Moto G4 แต่เมื่อฉันใช้โค้ดด้านบนมันก็ใช้ได้ดีสำหรับฉัน ขอบคุณ. คุณช่วยฉัน
Shailesh

6

แก้ไข: ใช้โซลูชันนี้ที่นี่: 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;
}

หมายเหตุ: เราจึงมีเอกสารและรูปภาพขึ้นอยู่กับว่ารูปภาพนั้นมาจาก "ล่าสุด" "แกลเลอรี" หรืออะไรก็ตาม ดังนั้นฉันจึงดึงรหัสภาพออกมาก่อนที่จะค้นหา


1

สวัสดีนี่คือรหัสที่สมบูรณ์ของฉันสำหรับการถ่ายภาพจากกล้องหรือร้านขายของชำ

// การประกาศตัวแปรของฉัน

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

//เมื่อคลิก

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

// method body

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

คุณรู้ได้อย่างไรว่า 100 ในบรรทัดนี้ options.inSampleSize = calculateInSampleSize(options, 100, 100);
John Joe

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.