출처: http://dark0946.tistory.com/archive/201407
이번에 대만 런칭 준비를 하며 디바이스 테스트를 해보던 중에 사진이 업로드 되지 않는 버그를 발견했다.
갤러리 호출 파트에서 디버깅을 해보니, Path 값이 들어오지 않아서 체크해보니 다음과 같이 나타남.
* 테스트 기종은 아래와 같으며, 두 디바이스 모두 Android Version - KitKat 으로 설치되어 있음.
* HTC Zara : content://com.android.providers.media.documents/document/image:1152 * Samsung Galaxy S4 : content://media/external/images/media/1152 * Google Drive에서 사진 가져올 시 : content://com.google.android.apps.photos.content/3/https://lh5.googleusercontent.com/ABCD-EFGH=KJ flg=0x1 |
* 추가
겔럭시 시리즈에서 사진을 Picasa에 자동업로드 해주는 기능을 지원합니다.
해당 사진들을 읽어오면 Uri Path가 다음과 같은 형식으로 잡힙니다.
content://com.sec.android.gallery3d.provider ...........
킷캣으로 업데이트 되면서 외부저장소 호출이 가능한 함수가 새로 생겨났다.
( * 킷캣 업데이트 내용은 여기에서 확인할 수 있음 )
그러면서 호출 경로 부분에서도 약간의 변화가 생겼다. 기본적으로 사용하던 갤러리의 경로 ( content://media/external/images/media/ ) 가 좀 더 세분화되었다. 그 덕분에(?) uri에 셋팅된 경로가 바뀌면서 Segement 값을 잘못 읽어들이거나, 읽어들일수 없게 되어, 오류가 발생하게 된다.
경로를 받아와서 사진 데이터를 읽어들이는 방식에 대한 예외처리 작업이 조금 필요하다.
다음 코드는 Intent 를 받아와 getData를 통해 전달받은 Uri값으로 경로를 받아오는 부분이다.
// 선택한 이미지 경로 가져오기. public final String getPath(Uri uri) {
// TEST // HTC: content://com.android.providers.media.documents/document/image:..... // GalaxyS4 : content://media/external/images/media/....
// * 기존에 갤러리에서 호출했던 방식. // Cursor c = mActivity.getContentResolver().query(Images.Media.EXTERNAL_CONTENT_URI, // null, // Images.Media._ID + "=?", // new String[] { uri.getLastPathSegment() } , // null); // @@@@@@ // content://com.android.providers.media.documents/document/image%.... // getAuthority = "com.android.providers.media.documents" // // content://media/external/images/media/.... // getAuthority = "media" //
final boolean isAndroidVersionKitKat = Build.VERSION.SDK_INT >= 19; // ( == Build.VERSION_CODE.KITKAT )
// Check Google Drive. if(isGooglePhotoUri(uri)) { return uri.getLastPathSegment(); }
// 1. 안드로이드 버전 체크 // com.android.providers.media.documents/document/image :: uri로 전달 받는 경로가 킷캣으로 업데이트 되면서 변경 됨. if(isAndroidVersionKitKat && DocumentManager.isDocumentID(uri)) {
//com.android.providers.media.documents/document/image:1234 ... // if(isMediaDocument(uri) && DocumentManager.isDocumentID(uri)) { final String docId = DocumentManager.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) { return null; // 필자는 이미지만 처리할 예정이므로 비디오 및 오디오를 불러오는 부분은 작성하지 않음.
} else if ("audio".equals(type)) { return null; }
final String selection = Images.Media._ID + "=?"; final String[] selectionArgs = new String[] { split[1] };
return getDataColumn(mActivity.getApplicationContext(), contentUri, selection, selectionArgs); }
}
// content://media/external/images/media/.... // 안드로이드 버전에 관계없이 경로가 com.android... 형식으로 집히지 않을 수 도 있음. [ 겔럭시S4 테스트 확인 ] if(isPathSDCardType(uri)) {
final String selection = Images.Media._ID + "=?"; final String[] selectionArgs = new String[] { uri.getLastPathSegment() };
return getDataColumn(mActivity.getApplicationContext(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs); }
// File 접근일 경우 else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); }
return null; }
// URI 를 받아서 Column 데이터 접근. public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null; final String column = "_data"; final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs ,null); if (cursor != null && cursor.moveToFirst()) { final int column_index = cursor.getColumnIndexOrThrow(column); return cursor.getString(column_index); }
} finally { if (cursor != null) cursor.close(); }
return null; }
// 킷캣에서 추가된 document식 Path public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority()); }
// 기본 경로 ( 킷캣 이전버전 ) public static boolean isPathSDCardType(Uri uri) { // Path : external/images/media/ID(1234...) return "external".equals(uri.getPathSegments().get(0)); }
// 구글 드라이브를 통한 업로드 여부 체크. public static boolean isGooglePhotoUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri.getAuthority()); } |
( * DocumentManager 는 API 19 SDK의 DocumentContract 와 동일합니다. 또는 여기 참고.)
* HTC Zara : content://com.android.providers.media.documents/document/image:1152 * Samsung Galaxy S4 : content://media/external/images/media/1152 From Google Drive : content://com.google.android.apps.photos.content/3/https://lh5.googleusercontent.com/ABCD-EFGH=KJ flg=0x1 |
결론은 uri.getAuthority() 와 uri.getLastPathSegement() 값을 분류해주는 작업만 잘 해주면 됨...
나머지 불러오는 방식은 일반 갤러리 호출 방식과 같음.
:: 참고 사이트 ::
- 갤러리 또는 SD카드에서 이미지를 선택했을 때 절대경로 받아오는 방법
- 안드로이드 킷캣(Kitkat - API 19 ) 정보
'IT_Programming > Android_Java' 카테고리의 다른 글
Android Studio Gradle 관련 빈번히 마주할 수 있는 오류사항 정리! (0) | 2015.03.18 |
---|---|
[펌] WindowManager의 OnTouch Event 처리하기 (0) | 2015.03.10 |
안드로이드 어플리케이션이 회전될 때 주의해야할 점 (0) | 2015.02.10 |
Scheduling Repeating Alarms (0) | 2015.01.20 |
TextView에 ScrollView로 감싸지 않고 스크롤되게 하기 (0) | 2015.01.14 |