프로젝트를 진행하다 보니 핸드폰의 갤러리 같은 기능을 만들어야 했습니다. 그래서 사용방법을 알아보니 다음과 같은 것들이 확인해야 했습니다.
안드로이드 디벨로퍼를 보면 공유 저장공간 개요라는 항목이 있고,
거기서 미디어 컨텐츠 관련 설명이 있습니다. (추가로 문서 및 기타 파일도 있는데 그건 넘어 가겠습니다.)
"시스템은 이러한 종류의 파일에 표준 공개 디렉터리를 제공하므로 사용자에게는 모든 사진에 사용하는 공통 위치, 모든 음악과 오디오 파일에 사용하는 또 다른 공통 위치 등이 있습니다. 앱은 플랫폼의 MediaStore API를 사용하여 이 콘텐츠에 액세스할 수 있습니다."
라고 안드로이드 디벨로퍼에 설명이 되어 있습니다.
그럼 어떻게 하면 핸드폰에 있는 미디어 데이터(그중에서 이미지 데이터)를 가져오는지 알아 보겠습니다.
기본은 다음과 같습니다.
val projection = arrayOf(media-database-columns-to-retrieve)
val selection = sql-where-clause-with-placeholder-variables
val selectionArgs = values-of-placeholder-variables
val sortOrder = sql-order-by-clause
applicationContext.contentResolver.query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)?.use { cursor ->
while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
}
}
위의 코드와 같이 미디어 저장소 추상화와 상호작용하려면 다음과 같이 앱 컨텍스트에서 검색한 ContentResolver 객체를 사용합니다.
그리고 시스템은 자동으로 외부 저장소 볼륨을 검색하고 다음과 같이 잘 정의된 컬렉션에 미디어 파일을 추가합니다. 그리고 다음과 같은 항목으로 설정할 수 있습니다.
- 이미지 - 사진 및 스크린샷을 포함하며, DCIM/ 및 Pictures/ 디렉터리에 저장됩니다. 시스템은 이러한 파일을 [MediaStore.Images] 테이블에 추가합니다.
- 동영상 - DCIM/, Movies/ 및 Pictures/ 디렉터리에 저장됩니다. 시스템은 이러한 파일을 [MediaStore.Video] 테이블에 추가합니다.
- 오디오 파일 - Alarms/, Audiobooks/, Music/, Notifications/, Podcasts/ 및 Ringtones/ 디렉터리에 저장된 오디오 파일과 Music/ 또는 Movies/ 디렉터리에 있는 오디오 재생목록이 포함됩니다. 시스템은 이러한 파일을 [MediaStore.Audio] 테이블에 추가합니다.
- 다운로드한 파일 - Download/ 디렉터리에 저장됩니다. Android 10(API 수준 29) 이상을 실행하는 기기에서는 이러한 파일이 [MediaStore.Downloads] 테이블에 저장됩니다. Android 9(API 수준 28) 이하에서는 이 테이블을 사용할 수 없습니다.
또한, 이 항목을 사용하려면 저장소 권한을 받아야 합니다.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
즉 간단히 설명하면
- 앱이 [READ_EXTERNAL_STORAGE] 권한을 부여받았습니다.
- 파일이 잘 정의된 다음 미디어 컬렉션 중 하나에 있습니다.
로 사용할 수 있습니다.
그럼 빠르게 안드로이드 폰 내에 있는 이미지 정보를 가져오는 방법을 보겠습니다.
data class MediaItem(
val id: Long,
val displayName: String,
val dateTaken: Date,
val contentUri: Uri
)
val imageList = mutableListOf<MediaItem>()
// 가져올 정보 선택
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_TAKEN
)
// 정렬 방식 선정
val sortOrder = "${MediaStore.Images.Media.DATE_TAKEN} DESC"
// contentResolver를 사용하여 query로 이미지 정보 호출
val query = context.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null, null, sortOrder
)
@SuppressLint("SimpleDateFormat")
private fun dateToTimestamp(day: Int, month: Int, year: Int): Long =
SimpleDateFormat("dd.MM.yyyy").let { formatter ->
formatter.parse("$day.$month.$year")?.time ?: 0
}
fun getGerryItem() : MutableList<MediaItem> {
query?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
val dateTakenColumn =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN)
val displayNameColumn =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val dateTaken = Date(cursor.getLong(dateTakenColumn))
val displayName = cursor.getString(displayNameColumn)
val contentUri = Uri.withAppendedPath(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id.toString()
)
imageList += MediaItem(id, displayName, dateTaken, contentUri)
}
}
return imageList
}
위와 같은 code로 작업을 하면 imageList에 이미지 관련 데이터들이 생성되고. 거기에 있는 uri를 사용하여 ImageView에 적용하면 됩니다.
만일 동영상 파일을 가져오려면
// Need the READ_EXTERNAL_STORAGE permission if accessing video files that your
// app didn't create.
// Container for information about each video.
data class Video(val uri: Uri,
val name: String,
val duration: Int,
val size: Int
)
val videoList = mutableListOf<Video>()
val projection = arrayOf(
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.SIZE
)
// Show only videos that are at least 5 minutes in duration.
val selection = "${MediaStore.Video.Media.DURATION} >= ?"
val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString()
)
// Display videos in alphabetical order based on their display name.
val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC"
val query = ContentResolver.query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)
query?.use { cursor ->
// Cache column indices.
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
val nameColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
val durationColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)
val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)
while (cursor.moveToNext()) {
// Get values of columns for a given video.
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
val duration = cursor.getInt(durationColumn)
val size = cursor.getInt(sizeColumn)
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
id
)
// Stores column values and the contentUri in a local object
// that represents the media file.
videoList += Video(contentUri, name, duration, size)
}
}
위의 코드는 안드로이드 디벨로퍼에 있는 코드 입니다
즉 이미지와 비디오는 따로 수집해와야하는 것 같습니다.
참고:
https://developer.android.com/training/data-storage/shared
https://developer.android.com/training/data-storage/shared/media
https://codechacha.com/ko/android-mediastore-read-media-files/
'2023년 이전 > Android' 카테고리의 다른 글
Camera 촬영 후 해상도가 낮아지는 현상 해결 방법 (1) | 2021.12.03 |
---|---|
ViewPager2에서 ui 업데이트 방법 (0) | 2021.12.03 |
onActivityResult / onRequestPermissionsResult deprecated (0) | 2021.12.03 |
Hilt를 사용한 ViewModel (0) | 2021.12.03 |
Hilt (0) | 2021.12.03 |