본문 바로가기
프로그래밍/Android

갤러리 앱 데이터 연동(ContentProvider)

by Mr-후 2018. 11. 1.
반응형


갤러리 앱 데이터 연동(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(); 

콜론( : )을 구분자로 문자열을 잘라서 앞 단어는 데이터의 타입, 뒷 단어는 데이터의 식별자로 사용한다. (출처 : 깡샘의 안드로이드 프로그램 중에서)


반응형