어떤 앱에서 자신이 사용하는 데이터를 다른 앱에 제공하기 위해 컨텐트 프로바이더(Content Provider)를 사용할 수 있습니다. 컨텐트 프로바이더를 제공하는 앱이 있으면 다른 앱에서는 컨텐트 리졸버(Content Resolver)를 만들어 컨텐트 프로바이더에서 제공하는 데이터를 받아올 수 있게 됩니다.
굳이 특정 앱이 아니더라도 안드로이드에서는 기기의 사진이나 연락처, 음악 데이터 등 여러 가지 데이터를 컨텐트 프로바이더를 통해 제공하고 있으므로 컨텐트 리졸버를 통해 해당 데이터를 가져올 수 있습니다.
현재 휴대폰에 저장된 음악목록을 가져오는 예시를 통해 컨텐트 리졸버의 활용방법을 간단히 알아보도록 하겠습니다.
우선 app -> manifests -> AndroidManifest.xml 파일에 다음 태그를 추가합니다. 안드로이드에서는 사진, 음악 등의 데이터는 MediaStore에 저장하고 있고 MediaStore에서는 각 미디어 종류마다 별도의 컨텐트 프로바이더를 제공하고 있습니다. 그런데 이 MediaStore는 외부 저장소에 해당하므로 외부 저장소에 접근하기 위한 권한이 필요한 것입니다.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
위에서 권한이 필요하다는 것을 명시하였으므로 해당 권한에 대한 처리를 구현합니다. 이를 위해 제일먼저 외부 저장소에 대한 권한이 있는지를 확인합니다.
fun checkPermission(view: View) {
val storagePermission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
if (storagePermission == PackageManager.PERMISSION_GRANTED) {
// 권한있음
}
else {
getPermission()
}
}
만약 권한이 없는 경우 사용자로부터 권한을 요청합니다. 만약 권한요청이 거부되면 앱을 곧장 종료하도록 합니다. 권한에 관해서는 이미 언급된 적이 있으므로 자세한 설명은 생략하도록 하겠습니다.
fun getPermission()
{
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
1 -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 권한 허용
}
else {
finish()
}
}
}
}
위에서 권한을 확인할때 권한이 주어져 있는 경우나 권한을 요청할 때 승인이 떨어진 경우 음악 목록을 가져오는 메서드를 작성합니다.
fun getMusicList()
{
}
이때 음악목록의 경우 MediaStore.Audio.Media.EXTERNAL_CONTENT_URI 상수를 통해 어디에서 데이터를 가져와야 하는지 지정할 수 있습니다.
fun getMusicList()
{
val mediaMusicURI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
해당 위치에서 데이터를 가져올 때 어떤 데이터를 가져올지를 지정합니다. 데이터베이스에서 URI가 테이블이라면 테이블의 어떤 칼럼을 가져올지를 지정하는 것이라고 보면 되겠습니다. 아래 예제에서는 음악의 고유 ID값과 제목을 가져올 수 있도록 하였습니다.
fun getMusicList()
{
val mediaMusicURI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val mediaMusicType = arrayOf(MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.TITLE)
}
어디서, 어떤 데이터를 가져올지가 정해졌으면 이를 컨텐트 리졸버를 통해 질의메서드에 실어 보내면 그 결과를 커서 형태로 반환하게 됩니다. 참고로 query메서드의 3번째 매개변수는 데이터 검색 시 검색 대상이 되는 칼럼을, 4번째는 3번째 매개변수에 지정한 칼럼에서 실제 검색 대상이 될 값을, 5번째는 데이터의 정렬순서를 지정합니다.
fun getMusicList()
{
val mediaMusicURI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val mediaMusicType = arrayOf(MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.TITLE)
val cursor = contentResolver.query(mediaMusicURI, mediaMusicType, null, null, null)
}
커서를 순회하면서 하나씩 데이터를 가져와 로그켓에 표시할 수 있도록 합니다. 이때 getColjumnIndex()는 지정한 값이 몇번째 칼럼인지에 대한 인텍스를 반환하며 getString()은 인덱스에 따른 실제 값을 반환합니다.
fun getMusicList()
{
val mediaMusicURI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val mediaMusicType = arrayOf(MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.TITLE)
val cursor = contentResolver.query(mediaMusicURI, mediaMusicType, null, null, null)
if (cursor != null) {
while (cursor.moveToNext()) {
var index = cursor.getColumnIndex(mediaMusicType[0])
var id = cursor.getString(index)
index = cursor.getColumnIndex(mediaMusicType[1])
var title = cursor.getString(index)
Log.i("test", "${id}--${title}")
}
}
}
이렇게 완성된 메서드를 위에서 선행한 권한처리관련 코드에 추가합니다.
fun checkPermission(view: View) {
val storagePermission = ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
if (storagePermission == PackageManager.PERMISSION_GRANTED) {
getMusicList()
}
else {
getPermission()
}
}
fun getPermission()
{
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
1 -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getMusicList()
}
else {
finish()
}
}
}
}
마지막으로 Activity에는 버튼 하나를 배치합니다. 그리고 속성 창에서 버튼의 onClick이벤트에 checkPermission() 메서드를 지정합니다. 위에서 checkPermission() 메서드 작성 시 view 매개변수를 지정한 것은 바로 이 때문입니다.
앱을 실행하고 버튼을 누르면 권한 요청이 표시되고 권한을 허용하면 정상적으로 음악의 목록이 표시됨을 확인할 수 있습니다.
'Mobile > Kotlin' 카테고리의 다른 글
[Kotlin] 권한의 이해 (0) | 2021.02.24 |
---|---|
[Kotlin] HttpURLConnection (2) | 2021.01.12 |
[Kotlin] 포어그라운드(Foreground) 서비스 (0) | 2021.01.08 |
[Kotlin] 서비스(Service) (2) | 2021.01.07 |
[Kotlin] AsyncTask (0) | 2021.01.06 |