development

안드로이드는 Uri.getPath ()로 실제 경로를 얻습니다.

big-blog 2020. 8. 27. 08:15
반응형

안드로이드는 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있습니까 ( ' ' 처럼 )?

감사


실제 경로를 얻는 것이 정말로 필요합니까?
예를 들어, ImageView.setImageURI()그리고 ContentResolver.openInputStream()당신은 그것의 실제 경로를 알 필요없이 파일의 내용을 액세스 할 수 있습니다.


이것이 제가하는 것입니다:

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()메서드는 더 이상 사용되지 않으므로 사용하지 않습니다.

마지막 편집 : 개선. 커서를 닫아야합니다 !!


@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/


2016 년 3 월 업데이트

이미지 경로의 모든 문제를 해결하기 위해 Facebook 및 기타 앱으로 사용자 지정 갤러리를 만들려고합니다. 이는 로컬 파일 (가상 또는 임시가 아닌 실제 파일) 만 사용할 수 있기 때문에이 라이브러리의 모든 문제를 해결합니다.

https://github.com/nohana/Laevatein (이 라이브러리는 카메라에서 사진을 찍거나 갤러리에서 선택하는 것입니다. 갤러리에서 선택하면 앨범이있는 서랍이 있고 로컬 파일 만 표시됩니다)


참고 이것은 @ user3516549 답변 의 개선 사항이며 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)
        }

    }

편집 : 더 높은 버전의 외부 sdcard 파일의 이미지 경로를 얻으려면 내 질문 을 확인하십시오 .


실제 길이 없습니다 .

UriA의 content방식은 일부 콘텐츠에 대한 불투명 핸들입니다. 이것이 Uri개방 가능한 콘텐츠 나타내는 경우 ContentResolver해당 콘텐츠 openInputStream()사용 하여 얻을 수 있습니다 InputStream. 마찬가지로, Urihttphttps방식은 로컬 파일을 나타내지 않는, 그리고 그 파일을 액세스하기 위해 HTTP 클라이언트 API를 사용해야합니다.

스키마 Uri가있는 만이 file파일을 식별합니다 (파일 Uri이 생성 된 후 이동 또는 삭제 된 경우 제외 ).

어리석은 사람들이하는 일은의 내용을 해독하려고 시도하여 파일 시스템 경로를 유도하려고하는 Uri$EVIL_DEITY입니다. 기껏해야 다음 세 가지 이유로 신뢰할 수 없습니다.

  1. Uri구조 Uri가 인터페이스가 아닌 구현 세부 사항을 나타내 므로 디코딩 규칙은 Android 버전 릴리스와 같이 시간이 지남에 따라 변경 될 수 있습니다.

  2. 파일 시스템 경로를 얻더라도 파일에 액세스 할 권한이 없을 수 있습니다.

  3. Uri많은 앱에 자체 공급자가 있고 자산에서 BLOB열, 인터넷에서 스트리밍해야하는 데이터 에 이르기까지 모든 값을 고정 알고리즘을 통해 디코딩 할 수있는 것은 아닙니다.

파일이 필요한 제한된 API가있는 경우 InputStreamfrom openInputStream()사용하여 해당 콘텐츠의 사본을 만드십시오. 임시 복사본 (예 : 파일 업로드 작업에 사용 된 다음 삭제됨) 또는 영구 복사본 (예 : 앱의 "가져 오기"기능)은 귀하에게 달려 있습니다.


편집 : 여기에서이 솔루션을 사용하십시오 : 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를 추출합니다.


Hii는 카메라 또는 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);
}

이것은 갤러리에서 uri를 얻고 멀티 파트 업로드 용 파일로 변환하는 데 도움이되었습니다.

File file = FileUtils.getFile(this, fileUri);

https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java

참고 URL : https://stackoverflow.com/questions/2789276/android-get-real-path-by-uri-getpath

반응형