갤러리 앱 데이터 연동(ContentProvider)
조만간, 주소록을 연동해야하는 개발 건이 준비되고 있긴 한데 아이폰의 경우 그동안 해온 작업이 많아 리소스가 확보되어 있어 구현하는데 어려움은 없을 것 같다. 안드로이드의 경우는 책을 보다 보니 컨텐츠 프로바이더를 시용하여 주소록, 갤러리 등 구글 기본앱과 연동해서 데이터를 교환할 수 있는 방식이다. 아이폰도 스킴을 이용해 PickViewController를 띄우는 방식이므로 비슷한 느낌이지만 데이터를 받는 느낌은 델리게이션과 좀 다른 듯 하다, 또 API Level에 따른 분기도 필요한 부분이라고 하니 정리를 해 두고자 한다.
갤러리 앱도 그렇지만 나의 경우 주소록 앱도 다중 선택이 많이 사용 되고 있는데 , 책에서는 갤러리 앱에서 여러 개를 선택했을 때에 대한 예만 제시가 되어 있어 갤러리 앱의 데이터를 획득하는 방법에 대해 정리를 한다.
우선 인텐트를 발생시켜 갤러리 앱을 띄워 준다.
단 API Level 16 이전 버전과 상위 버전에 대한 분기를 해야 한다.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { //스마트폰 버전 정보는 Build.VERSION.SDK_INT로 얻는다.
//jelly bean 하위버전에서는 하나만 선택 가능.
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(MediaStore.Images.Media.CONTENT_TYPE);
intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 20);
} else {
//여러 파일 정보를 획득하는 ClipData가 jelly_bean에서부터 제공.
Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, 30);
}
startActivityForResult()를 이용하는 경우 onActivityResult()를 Override해야하므로 각각의 경우 갤러리 앱으로부터 데이터를 획득하는 방식은 다음과 같다.
//jelly bean 이전 버전 -> 하나만 선택된 이미지
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(data.getData(), projection, null, null, null);
cursor.moveToFirst();
String filePath = cursor.getString(0);
query함수의 3번째 매개변수가 where 조건이지만 null로 지정한 이유는 첫 번째 매개변수의 Uri객체에 설정된 URL 경로에 사용자가 선택한 이미지의 식별자 값이 포함되어 있으므로where조건이 없어도 사용자가 선택한 파일을 지징할 수 있기 때문이다.
다음은 API Level 16이상 버전에서 선택된 데이터를 획득하는 코드다. 해당 정보가 ClipData타입으로 전달된다.
if (data.getClipData() != null {
//여러장이 넘어온 경우
ClipData clipData = data.getClipData();
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.item item = clipData.getItemAt(i);
Uri uri = item.getUri();
//kicat에서 추가된 document식 path (다른 방식은 '세그먼트식 경로'도 있다.)
if ("com.android.providers.media.documents".equals(uri.getAuthority()) && Build.VERSION.SDK_INT >= 19 ) {
//....
} else if ("external".equals(uri.getPathSegments().get(0))) {
// ...
}
} //exit for
} else {
//하나만 선택해서 넘어온 경우
}
API Level 19버전부터 ClipData에 포함된 이미지의 Uri값이 content://com.android.providers.media.documents/document/image:3A23420 와 같은 형태로 전달, 그리고 그 하위버전이나 19버전 이상의 스마트폰이더라도 스마트폰에 따라 Uri값이 세그먼트식 경로로 전달 될 수 있다. (거지 같다...음)
세그먼트식 경로에서 이미지를 획득하는 방법
사용자가 선택한 이미지의 파일 경로를 컨텐츠 프로바이더를 이용하여 획득.
String section = MediaStore.Images.Media._ID + "?";
String[] selectionArgs = new String[] {uri.getLastPathSegment()};
String column = "_data";
String[] projection = {column};
Cursor cursor = getcontentResolver()
.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null);
String filepath = null;
if (cursor != null && cursor.moveToFirst()) {
int column_index = cursor.getColumnIndexOrThrow(column);
filepath = cursor.getString(column_index);
}
cursor.close();
도큐먼트식 경로의 경우
경로에서 "document" 뒤에 있는 image: ~ 의 정보가 필요하기 때문에 String docId = DocumentsContract.getDocumentId(uri);를 통해 추출할 수 있다.
String docId = DocumentsContract.getDocumentId(uri);
String[] split = docId.split(":");
String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) { //video, audio 사용 가능
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
String selection = MediaStore.Images.Media._ID + "=?";
String[] selectionArgs = new String[][split[1]};
String column = "_data";
String[] projection = {column};
Cursor cursor = content.getContentResolver().query(contentUri, projection, selection, selectionArgs, null);
String filePath = null;
if (cursor != null && cursor.movetoFirst()) {
int column_index = cursor.getColumnIndexOrThrow(column);
filePath = cursor.getString(column_index);
}
cursor.close();
콜론( : )을 구분자로 문자열을 잘라서 앞 단어는 데이터의 타입, 뒷 단어는 데이터의 식별자로 사용한다. (출처 : 깡샘의 안드로이드 프로그램 중에서)
'프로그래밍 > Android' 카테고리의 다른 글
SMS수신 처리 (0) | 2018.11.02 |
---|---|
ConnectivityManager 네트워크 접속 정보 얻기 (0) | 2018.11.02 |
설치된 앱 목록 조회(PackageManager) (0) | 2018.10.31 |
Android 최상위 액티비티 확인 방법 (0) | 2018.10.31 |
Failed to resolve: play-services-basement (0) | 2018.10.30 |