android lấy đường dẫn thực bằng Uri.getPath ()


107

Tôi đang cố lấy hình ảnh từ thư viện.

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

Sau khi tôi trở lại từ hoạt động này, tôi có một dữ liệu, trong đó có Uri. Nó có vẻ như:

content://media/external/images/1

Làm cách nào để chuyển đổi đường dẫn này thành đường dẫn thực (giống như ' /sdcard/image.png')?

Cảm ơn


1
Đây rõ ràng là một nhận xét rất muộn, nhưng tôi chỉ muốn chỉ ra rằng phương thức startActivityForResultCode lấy mã yêu cầu làm đối số, không phải mã kết quả.
Tianxiang Xiong

đã uri.getPath()không cung cấp cho bạn con đường thực sự?
Darpan

# Hãy thử vẫn tiếp tục này, nếu bạn đang gặp vấn đề để tìm ra con đường thực sự, bạn có thể thử các câu trả lời của tôi. Câu trả lời trên không giúp tôi. Giải thích : - Phương pháp này lấy URI và sau đó kiểm tra cấp độ API của thiết bị Android của bạn sau đó theo cấp độ API nó sẽ tạo ra Đường dẫn thực. Mã để tạo đường dẫn thực khác nhau tùy theo các cấp API. Đây là câu trả lời của tôi
Sunil

Câu trả lời:


56

Có thực sự cần thiết cho bạn để có được một con đường vật lý?
Ví dụ, ImageView.setImageURI()ContentResolver.openInputStream()cho phép bạn truy cập nội dung của một tệp mà không cần biết đường dẫn thực của nó.


Đó chính xác là những gì tôi đã tìm kiếm, nhưng không thể tìm thấy. Cảm ơn.
davs

6
Xin lỗi và Nếu tôi muốn chuyển đổi hình ảnh này thành tệp mà không có đường dẫn thực thì phải làm thế nào?
Chlebta

6
Đường dẫn vật lý cấp quyền truy cập vào tên tệp và phần mở rộng. Trong trường hợp tải lên tệp.
clocker

195

Đây là những gì tôi làm:

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

và:

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

LƯU Ý: managedQuery()phương pháp không được dùng nữa, vì vậy tôi không sử dụng nó.

Lần sửa cuối: Cải tiến. Chúng ta nên đóng con trỏ !!


1
stackoverflow.com/a/7265235/375093 Đây là một tùy chọn khác, nhưng được đề xuất là tốt hơn ở trên. Kiểm tra cái này quá
Sundeep

6
Xin chào @ m3n0R, Trong Moto G, cột MediaStore.Images.ImageColumns.DATA hoàn toàn không tồn tại. Làm thế nào để có được hình ảnh mà không có cột này?
dường như

16
LỖI Hãy chắc chắn rằng con trỏ được khởi tạo một cách chính xác trước khi truy cập dữ liệu từ nó .. check-in API 19
Mayur R. Amipara

1
@ReneJuuse: Tài nguyên tuyệt vời. Cuối cùng tôi đã giải quyết được vấn đề này nhờ đó - tôi không nhận ra rằng có quá nhiều thay đổi kể từ khi Android ra đời. Tôi đang chạy API 21 và khi tôi sử dụng triển khai API 19 được hiển thị trên trang web bạn đã liên kết, cuối cùng nó đã hoạt động.
Milos Ivanovic

2
Không thể đọc hàng 0, cột -1 từ CursorWindow. Đảm bảo Con trỏ được khởi tạo chính xác trước khi truy cập dữ liệu từ nó.
Maveň ツ

18

@Rene Juuse - ở trên trong nhận xét ... Cảm ơn liên kết này!

. mã để lấy đường dẫn thực có một chút khác biệt từ SDK này sang SDK khác, vì vậy bên dưới chúng tôi có ba phương pháp xử lý các SDK khác nhau.

getRealPathFromURI_API19 (): trả về đường dẫn thực cho API 19 (hoặc cao hơn nhưng chưa được kiểm tra) getRealPathFromURI_API11to18 (): trả về đường dẫn thực cho API 11 đến API 18 getRealPathFromURI_below11 (): trả về đường dẫn thực cho API dưới 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);
}

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


CẬP NHẬT Tháng 3 năm 2016

Để khắc phục tất cả các vấn đề với đường dẫn của hình ảnh, tôi thử tạo một thư viện tùy chỉnh dưới dạng facebook và các ứng dụng khác. Điều này là do bạn chỉ có thể sử dụng các tệp cục bộ (tệp thực, không phải tệp ảo hoặc tạm thời), tôi giải quyết tất cả các vấn đề với thư viện này.

https://github.com/nohana/Laevatein (thư viện này dùng để chụp ảnh từ máy ảnh hoặc chọn từ thư viện, nếu bạn chọn từ thư viện, anh ấy có một ngăn kéo với các album và chỉ hiển thị các tệp cục bộ)


@Clocker trên Samsung S4 không
Ricardo

Tôi thực sự khó quản lý tất cả các loại hình ảnh nguồn trong Android. Nếu bạn tải lên hoặc chọn từ thư viện, giải pháp tốt nhất là tạo dưới dạng thư viện từ facebook. Nó là một thư viện tùy chỉnh chỉ với hình ảnh thực trong thiết bị, không có ảo hoặc tạm thời. Tôi khắc phục tất cả các sự cố trong ứng dụng của mình bằng thư viện này. github.com/nohana/Laevatein Thư viện thực sự tốt của nó. Để tùy chỉnh không đơn giản, nhưng bạn có thể mở mã và thực hiện các thay đổi của mình. Tôi hy vọng điều này có thể giúp bạn.
luizfelipetx

Bị hỏng trên Samsung S2 của tôi với 4.4.1
Oliver Dixon

Tôi cần lấy các tệp như pdf hoặc doc, tôi không thể lấy được đường dẫn. Bạn có thể giúp tôi không?
Anish Kumar

1
Tuyệt vời! Cuối cùng là một cái gì đó thực sự hoạt động. Đã tìm kiếm điều này trong một thời gian dài. Cảm ơn.
Javatar

14

Lưu ý Đây là một cải tiến trong câu trả lời @ user3516549 và tôi đã kiểm tra nó trên Moto G3 với Android 6.0.1.
Tôi gặp sự cố này vì vậy tôi đã thử câu trả lời của @ user3516549 nhưng trong một số trường hợp, nó không hoạt động bình thường. Tôi nhận thấy rằng trong Android 6.0 (hoặc cao hơn) khi chúng tôi bắt đầu ý định chọn hình ảnh trong thư viện thì một màn hình sẽ mở ra hiển thị các hình ảnh gần đây khi người dùng chọn hình ảnh từ danh sách này, chúng tôi sẽ nhận được

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

trong khi nếu người dùng chọn thư viện từ ngăn kéo trượt thay vì gần đây thì chúng tôi sẽ nhận được URL

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

Vì vậy, tôi đã xử lý nó trong 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)
        }

    }

CHỈNH SỬA: nếu bạn đang cố lấy đường dẫn hình ảnh của tệp trong sdcard bên ngoài ở phiên bản cao hơn thì hãy kiểm tra câu hỏi của tôi


Chào bạn, đúng vậy. nhưng điều này đang xảy ra vì bây giờ google có định dạng mặc định để tải tất cả ảnh từ điện thoại của bạn lên google docs. Và chỉ cần lưu thumbinal trong điện thoại của bạn. Nếu bạn nhận được tiểu này từ tài liệu google, bạn cần tải ảnh xuống trước khi sử dụng. Điều này nói chung là không tốt. Vì vậy, để khắc phục tất cả các vấn đề ở đây, bây giờ tôi đang sử dụng thư viện này. (thư viện này chỉ sử dụng các tệp cục bộ và với giải pháp này, vấn đề của bạn sẽ được giải quyết), hoặc bạn có thể trích xuất mã từ thư viện và tự cải thiện để giải quyết vấn đề của mình. github.com/nohana/Laevatein Tôi hy vọng điều này có thể giúp bạn.
luizfelipetx

1+, công việc của nó hoàn hảo đối với tôi. Như @JaiprakasSoni đã nói trong câu trả lời của mình rằng tôi đã gặp phải vấn đề tương tự khi chạy ứng dụng của mình trong Moto G4 play nhưng khi tôi sử dụng mã trên, nó hoạt động tốt đối với tôi. Cảm ơn bạn. Bạn tiết kiệm thời gian của tôi
Shailesh

6

CHỈNH SỬA: Sử dụng Giải pháp này tại đây: https://stackoverflow.com/a/20559175/2033223 Hoạt động hoàn hảo!

Đầu tiên, cảm ơn giải pháp của bạn @luizfelipetx

Tôi đã thay đổi giải pháp của bạn một chút. Điều này phù hợp với tôi:

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

Lưu ý: Vì vậy, chúng tôi có tài liệu và hình ảnh, tùy thuộc, nếu hình ảnh đến từ 'gần đây', 'thư viện' hoặc từ trước đến nay. Vì vậy, tôi giải nén ID hình ảnh đầu tiên trước khi tìm kiếm nó.


1

Xin chào, đây là mã hoàn chỉnh của tôi để chụp ảnh từ máy ảnh hoặc kính

// Khai báo biến của tôi

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

//Trong một cái nhấp chuột

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

// phần thân của phương thức

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

// Và những thứ còn lại

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

Làm thế nào bạn biết là 100 trong dòng này options.inSampleSize = calculateInSampleSize(options, 100, 100);
John Joe

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.