이 글은 이것이 안드로이드다 with 코틀린(개정판)를 참고하여 작성하였습니다.
작성자 : 강소영
개발환경은 Windows, Android Studio입니다.
ContentResolver를 이용해 뮤직 플레이어 만들기(음원 목록 가져오는 앱 만들기)
Intro.
ContentResolver?
Content Provider의 결과를 반환하는 브릿지 역할을 해주는 것. 컨텐트 프로바이더의 주소를 통해 데이터에 접근해 결과를 가져온다.
(Content Privider : 어플리케이션 사이에서 데이터를 공유하는 통로 역할을 함. 각종 설정값이나 DB에 접근하게 해준다.)
1. 음원 다운로드 받기 (외부 저장소에 접근하기)
Emulator에서 Chrome과 같은 웹 브라우저를 열어 검색창에 "free mp3 downloads last.fm"라고 검색하고 접속한다.
↓모양 버튼을 눌러 아무 노래나 원하는 만큼 다운로드 받고 기본 메뉴로 돌아가 Play Music 앱을 실행시켜 음원이 잘 다운되었는지 확인한다.
2. 다운로드 받은 음원 목록을 화면에 나타내는 코드 작성
외부 저장소에 저장된 음원 목록을 불러오기 위해 app->manifests에 권한을 추가하고 MainActivity에 추가한 권한을 선언해준다.
<uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE"/>
//manirests에 작성해야하는 권한을 추가하는 코드
val permissions = arryOf(Manifest.permission.READ_EXTERNAL_STORAGE)
//MainActivity의 Class 안에 작성해준다.
permissions에 권한이 있는가를 감별해내는 코드를 작성하기 위해 우선 사용자 지정 함수를 선언하고 나머지 코드를 작성해준다.
fun isPermitted() : Boolean { //imPermissed 말고 다른 이름으로 작성해도 된다.
...
}
사용자 지정 함수 isPermitted()의 위쪽에 조건문을 사용해 권한 감별 코드를 작성해준다.
if(isPermitted()) {
startProcess() //권한 있을경우 프로그램 진행
} else {
ActivityCompat.requestPermissions( activity: this, arrayOf(permission), REQ_READ) //권한 없을경우 앱 종료. 위쪽에 val permission = Manifest.permission.READ_EXTERNAL_STORAGE와 val REQ_READ = 99도 선언해준다.
}
fun startProcess() {
}//조건문 내의 코드를 밖으로 빼내서 작성해 가독성 올리기. (어쩔 수 없이 뺴낸 것도 있음. 만약 승인이 되지 않았을경우 코드를 다시 한 번 작성하는것을 방지하기 위한 용도.)
isPermitted()의 아래쪽에 onRequestPermissionResult 호출
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Arrary<out String>,
grantResults: IntArray
) {
if(requestCode == REQ_READ) { //requestCode가 맞는지 확인
if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startProcess()
} else {
Toast.makeText( context: this, "권한 요청 승인시에만 앱 실행 가능", Toast.LENGTH_LONG).show() //넣으면 좋은 코드. 안넣어도 됨.
finish() //GRANT가 아니면 앱 종료.
}
}
}
미리 선언해둔 isPermitted 함수의 몸체를 작성해준다.
fun isPermitted() : Boolean {
return ContextCompat.checkSelfPermission( context: this, permission) == PackageManager.PERMISSION_GRANTED) {
}
3. 화면 구성하기
RecyclerView 생성 후 Constraint 연결
RectclerView 안에 들어가는 음원 목록을 보여줄 item 레이아웃을 생성해주고, 화면에 ImageView와 TextView를 적당히 생성/배치해준다. 보기 좋게 글자 크기를 조정해주어도 된다.
(item 레이아웃 생성 : res->layout->New->Layout Resource File)
나중에 헷갈리지 않도록 텍스트 id를 바꾸어준다.
ex)아티스트 이름이 들어가는 텍스트 id를 textArtist로 변경.
화면을 돌려보고 깨지지 않으면 다음 단계로 넘어간다.
RecyclerView->Common Attributes->listitem의 맨 오른쪽에 있는 세로로 긴 조그마한 버튼을 클릭하면 미리 만들어놓은 item Layout을 불러올 수 있다.
RecyclerView의 id까지 지어주면 Layout 구성이 완료된다.
4. Class 생성
contentresolve -> New -> Kotlin File/Class를 통해 노래 제목, 아티스트 이름 등 음악과 관련된 데이터를 넣을 수 있는 코틀린 클래스를 생성한다.
class Music(id:String, title:String?, artist:STring?, albumId:String?, duration:Long?) { //Class 이름은 마음대로 지어도 됨.
var id:String = "" //음원 자체의 id
var title:String? = "" //노래 제목
var atrist:String? = "" //아티스트
var albumId:String? = "" //앨범의 이미지(자켓사진) id
var duration:Long? = 0 //음원 길이
} //음원 자체의 id값을 제외한 값들은 값이 없을 수 있으므로 null 처리를 해준다.
init {
this.id = id //this를 통해 id가 class에 속한 변수임을 알려줌.
this.title = title
this.artist = artist
this.albunId = albumId
this.duration = duration
}
fun getMusicUri(): Uri { //음원의 URI 주소를 호출하는 함수 생성.
return Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_COMTENT_URI, id)
} //이 코드를 통해 음원이 있는 주소를 반환시킨다.
fun getAlbumUri(): Uri { //앨범 URI를 가져오는 함수 생성
return Uri.parse( uriString: "content://content://media/external/audio/albumart/$albunId")
} //이 코드를 통해 앨범 이미지를 반환시킨다.
위를 마치면 contentresolve -> New -> Kotlin File/Class를 통해 MusicAdapter 클래스를 생성해준다.
//Holder는 MusicAdapter Class를 구성하기 전 미리 만들어놓고 클래서 구성 후 마무리한다.
class MusicAdapter : RecyclerView.Adapter<Holder>() {
val musicList = mutableListOf<Mustic>() //adapter가 사용한 컬렉션의 변수 정의.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.content)//화면에서 사용되는 목록의 최대 개수만큼 아이템 레이아웃 생성.
.inflate(R.layout.item_layout, parent, attatchToRoot: false)
return Holder(view) //view를 Holder에 담아 반환해 안드로이드가 사용하도록 부여.
}
override fun getItemCount(): Int{
return musicList.size//사용할 데이터의 개수를 알려줌.
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val music = musicList[position] //화면에 보여주는 것들을 그려주는 코드
holder.setMusic(music)
} //Ctrl + i로 함수 구현.
}
class Holer(itemView: View) :RecyclerView.ViewHolder(itemView) {
var musicUri:Uri? = null //현재 music URI를 저장하는 변수.
fun setMusic(music:Music) {
musicUri = music.getMusicUri()
itemView.imageAlbum.setImageURI(music.getAlbumUri())
itemView.textArtist.text = music.artist
itemView.textTitle.text = music.title
val sdf = SimpleDateFormat( pattern: "mm:ss" ) //분, 초까지만 표시
itemView.textDuration.text = sdf.format(music.duration)
}
}
MainActivity의 startProcess에서 음원을 가져오는 코드를 작성하고, startProcess의 하단에 음원 목록을 가져오는 코드를 작성해준다.
fun startProcess() {
val adapter = MusicAdapter()
adapter.musicList.addAll(getMusicList())
recyclerView.adapter = adapter //adapter를 recyclerView에 연결.
recyclerView.layoutManager = LinearLayoutManager( context: this)
}
fun getMusicList():List<Music> { //getMusicList 호출 & 컨텐트 리졸버로 음원 목록 가져오기
val musicListUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI //데이터 테이블 주소
//가져올 데이터 컬럼 정의
val proj = arrayOf(
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media._DURATION
)
//컨텐트 리졸버에 해당 데이터 요청
val cursor = contentResolver.query(musicListUri, proj, selection: null, selectionArgs: null, setOrder: null)
//커서로 전달받은 데이터를 꺼내서 저장
val musicList = mutableListOf<Music>()
while(cursor?.moveToNext() ?: false) { //null이면 while문이 작동하지 않으므로 이를 대비해 null일 경우 false임을 명시해준다.
val id = cursor!!.getString( columnlndex: 0)
val title = cursor!!.getString( columnlndex: 1)
val artist = cursor!!.getString( columnlndex: 2)
val albumId = cursor!!.getString( columnlndex: 3)
val duration = cursor!!.getLong( columnlndex: 4)
val music = Music(id, title, artist, albumId, duration)
musicList.add(music)
}
return musicList
}
코드 작성을 완료하면 Emulator로 실행해본다.
'GDSC HUFS 3기 > Android with Kotlin Team 2' 카테고리의 다른 글
[2팀] 34 Android AsyncTask의 구조와 제작 사항 (0) | 2021.12.06 |
---|---|
[2팀]31,32 Android 서비스, 포어그라운드 서비스 (0) | 2021.12.01 |
[2팀]쓰레드 타이머, 코루틴 이미지 다운로드 (0) | 2021.11.29 |
[2팀]16 Android와 SQLite 데이터 베이스 (0) | 2021.11.25 |
[2팀]16 파일 입출력 (0) | 2021.11.24 |