마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

갤러리 이미지 절대경로

0 추천

https://hhhhhhhong.tistory.com/28

해당블로그 보고 갤러리 이미지 절대경로를 가져오려고 해봤으나 

Caused by: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.

라고나옵니다.. 구글링해봐도 잘 안나오네요

현재 uri 까지 잘끌고오고 이미지뷰에도 글라이드 통해서 뿌려봤는데 잘 됩니다만 

private fun getPath(uri : Uri) {

    var result = ""
    var cursor : Cursor = activity?.contentResolver?.query(uri, null, null, null, null)!!

    if(cursor == null) {
        result = uri?.path.toString()
    }else {
        cursor.moveToFirst()
        var idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA)
        result = cursor.getString(idx)
        cursor.close()
    }
    Log.e("tag", "절대 "+ result)
}

현재 이렇게 썼는데 익셉션이 저렇게 터집니다.. 뭘까요..?

 

수원통학러 (3,570 포인트) 님이 2020년 12월 28일 질문

1개의 답변

0 추천
안드로이드에서 사진을 가져오는 코드는 정말 많이 변했습니다.
오래된 소스를 가져왔을 경우 안됩니다. 저도 최근에 예전에 쓰던 코드가 안되어 삽질을 했죠.
코틀린으로 변환해서 테스트는 되었습니다만, deprecated 문제가 있긴 하네요.
이게 버전 이슈가 있을 것 같은데, 일단 동작은 하지만 나중에 보완하셔야 할 듯..

        fun getFullPath(ctx : Activity, uri : Uri): String {

            var result = ""
            val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
            var cursor : Cursor = ctx?.contentResolver?.query(uri, filePathColumn, null, null, null)!!

            if(cursor == null) {
                result = uri?.path.toString()
            }else {
                cursor.moveToFirst()
                var idx = cursor.getColumnIndex(filePathColumn[0])
                result = cursor.getString(idx)
                cursor.close()
            }
            Log.e("tag", "절대 "+ result)

            return result;
        }

위의 코드가 잘 동작하지만,
MediaStore.Images.Media.DATA 가 deprecated 이슈가 있어서,
아래로 수정합니다.
파일 업로드도 잘되네요.
이후에 갤러리에서 가져올 때 오류가 있어서 수정합니다.
좀 더 간결하게 만들 수 있을 것 같은데,
폰 이슈가 있을 것 같아서 아래로 정리합니다.

    public static String getFullPathFromUri(Context ctx, Uri fileUri) {
        String fullPath = null;
        final String column = "_data";
        Cursor cursor = ctx.getContentResolver().query(fileUri, null, null, null, null);
        if (cursor != null) {
            cursor.moveToFirst();
            String document_id = cursor.getString(0);
            if (document_id == null) {
                for (int i=0; i < cursor.getColumnCount(); i++) {
                    if (column.equalsIgnoreCase(cursor.getColumnName(i))) {
                        fullPath = cursor.getString(i);
                        break;
                    }
                }
            } else {
                document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
                cursor.close();

                final String[] projection = {column};
                try {
                    cursor = ctx.getContentResolver().query(
                            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            projection, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
                    if (cursor != null) {
                        cursor.moveToFirst();
                        fullPath = cursor.getString(cursor.getColumnIndexOrThrow(column));
                    }
                } finally {
                    if (cursor != null) cursor.close();
                }
            }
        }
        return fullPath;
    }
Will Kim (43,170 포인트) 님이 2020년 12월 28일 답변
Will Kim님이 2020년 12월 31일 수정
현재 붙여서 해봤는데.. Caused by: java.lang.IllegalStateException: cursor.getString(idx) must not be null
커서가 널이라고나오는데.. 저기서 그대로 복붙하고 바뀐건 프래그먼트라서
ctx:Activity 파라미터빼고, ctx대신 activity를 넣어줬습니다만.. 왜일까요..?
테스트한건 andorid 10입니다
if(cursor.getType(idx) == FIELD_TYPE_STRING) {
                result = cursor.getString(idx)
            }
로 익셉션은 안나나 로그에 절대만 찍히고 아무것도안나오네요..
프레그먼트에서 넘길 때는 getActivity()로 넘기신 거죠?
매니페스트에 아래 문구가 있는거죠?
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

그리고 동적으로 퍼미션 체크를 하신거죠?
Uri가 갤러리에서 넘어온 정상적인 Uri인가요?
아래처럼 갤러리 호출한 것인지 확인 해 보세요.

val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
            startActivityForResult(Intent.createChooser(intent, "프로파일 사진 선택"), GalleryFragment.SELECT_PICTURES)
아 그리고 질문이 여기에 두번 올라왔는데, 아래것은 지우시는게 좋을 것 같네요.
안드로이드 10 이라그런건지.. 분명 전에는 권한체크했던거같은데
여기선 권한없이도 끌어와지더라구요 scope storage 때문인건지 모르겠는데.. 상대경로? 가져와서 글라이드로 뿌리면 잘뿌려집니다
val contentValues = ContentValues()

        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/test/")
 val resolver = activity?.contentResolver
        var test = resolver?.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
답변올려주시는사이 이런방법도 해봤는데
content://media/external/images/media/16594
이렇게 나오는게 절대경로 맞지않나요..? 글라이드로 찍어보면 또 얘는안나오네요
startactivityforresult가 디프리케이트되서.. launcher.launch("image/*") 이렇게 인텐트 써주고있습니다
/storage/emulated/0/Download/9bec60d4c8e7b0d09f1b29ed9777793e.jpg

이렇게 나와야 정상이고, 위에는 contenturi 그대로인 것 같네요.

아 그러고보니, Manifest에서
<application 안에

android:requestLegacyExternalStorage="true"
이걸 넣어보세요.
테스트폰이 오래된 거라면 먹힐 수도
현재 저의 폰으로 사용하고있는데.. ㅠㅠ s10입니다  매니페스트에 붙여봤는데 안나오네요..
file_layout.setOnSingleClickListener {
            launcher.launch("image/*")
        }
현재 이게 startactivityforresult고


    private val launcher =
            registerForActivityResult(ActivityResultContracts.GetContent()) { result: Uri? ->
                Log.e("tag", "url "+ result?.path)
                getPath(result!!)
                activity?.let { Glide.with(it).load(result).into(imgview) }
이게 onactivityresult입니다
일단 그냥 startactivityforresult onactivityresult로 쓰니까 되긴되네요 감사합니다
문제는 deprecate...
JAVA에서는 표시가 나지않아 deprecated인지 몰랐죠.
코틀린으로 바꾸니까 바로 표시나네요.

파일을 복사하거나 서버로 업로드하지 않을거라면,
pic.setImageURI(selectedImage);
그냥, 이렇게 Uri로 이미지 뷰를 바로 Uri로 표시하거나
Glide로도 아래와 같이하면 Uri로 바로 표시 가능합니다.
Glide.with(getActivity()).load(imageUri).into(imageProfile);

샘플이 Java 지만, 금방 변환이 가능하므로...
서버로 업로드할거라.. 구글링해보니 절대경로로 해야된다해서 절대경로를 구해야됩니다 ㅠㅠ
코틀린에 이런게 있네요. 1.3.0 이상이어야 합니다.

uri.toFile()

--> 제 개발환경에서는 오류가 나서 코멘트 남깁니다.
deprecated 문제를 해결한 버전입니다.
추가로 갤러리에서 가져올 때 오류도 수정했습니다.
위에 답변을 아래로 수정하겠습니다.

    public static String getFullPathFromUri(Context ctx, Uri fileUri) {
        String fullPath = null;
        final String column = "_data";
        Cursor cursor = ctx.getContentResolver().query(fileUri, null, null, null, null);
        if (cursor != null) {
            cursor.moveToFirst();
            String document_id = cursor.getString(0);
            if (document_id == null) {
                for (int i=0; i < cursor.getColumnCount(); i++) {
                    if (column.equalsIgnoreCase(cursor.getColumnName(i))) {
                        fullPath = cursor.getString(i);
                        break;
                    }
                }
            } else {
                document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
                cursor.close();

                final String[] projection = {column};
                try {
                    cursor = ctx.getContentResolver().query(
                            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            projection, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
                    if (cursor != null) {
                        cursor.moveToFirst();
                        fullPath = cursor.getString(cursor.getColumnIndexOrThrow(column));
                    }
                } finally {
                    if (cursor != null) cursor.close();
                }
            }
        }
        return fullPath;
    }
...