이번시간에는 재생버튼을 눌렀을때 1초마다 시간과 progressbar가 갱신되고, 정지버튼을 누르면 멈출수있도록 만들어보겠다
# Seekbar적용
activity_song으로 가서 progressbar를 SeekBar로 적용해준다
SeekBar는 사용자가 값을 선택할수있는 슬라이더 형태의 바를 말한다
<SeekBar
android:id="@+id/song_progress_sb"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_marginTop="5dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:background="@null"
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:progress="0"
android:max="100000"
android:progressBackgroundTint="@color/gray_color"
android:progressTint="@color/select_color"
android:thumb="@color/transparent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/song_like_iv_layout"/>
progress는 SeekBar 의 현재진행상태를 나타내는데 0으로 초기화해주었다
progressBackgroundTint, progressTint를 사용해서 SeekBar의 기본색상과 진행상태일때의 색상을 설정해준다
thumb는 transparent로 설정해서 표시되지 않도록해준다
max는 100,000으로 설정해서 가독성이 떨어지지 않게해준다 (기본 설정값은 100이다)
# Song 데이터 클래스 수정
//데이터 클래스
data class Song(
val title : String = "", //노래제목
val singer : String = "", //가수
var second : Int = 0, //현재 재생시간
var playTime : Int = 60, //총 재생시간
var isPlaying : Boolean = false //노래가 현재 재생되고 있는지
)
Song 데이터 클래스를 위와같이 수정해준다
현재 재생시간, 총재생시간,재생중인지에 해당하는 데이터를 추가했다
총 재생시간은 60초라고 가정했다
# MainActivity
// text값들을 string값으로 바꿔서 가져오기 (title,singer,second,playTime,isPlaying에 해당하는 값들)
val song = Song(binding.mainMiniplayerTitleTv.text.toString(), binding.mainMiniplayerSingerTv.text.toString(),0,60,false)
//binding을 사용해서 id값 가져오기
//mainPlayerCl눌렀을때 SongActivity로 이동
binding.mainPlayerCl.setOnClickListener {
//startActivity(Intent(this, SongActivity::class.java))
val intent = Intent(this, SongActivity::class.java)
//putExtra를 사용해서 데이터값들을 보내줌
intent.putExtra("title", song.title) //putExtra를 사용해서 title(제목)데이터를 보내줌
intent.putExtra("singer", song.singer) //putExtra를 사용해서 singer(가수)데이터를 보내줌 (보낸데이터는 SongActivity에서 받음)
intent.putExtra("second", song.second)
intent.putExtra("playTime", song.playTime)
intent.putExtra("isPlaying", song.isPlaying)
startActivity(intent)
}
MainActivity에 있는 내용을 수정해준다
putExtra를 사용해서 SongActivity로 데이터값들을 보내준다
# SongActivity에 initSong함수와 setPlayer함수 추가
//Song 데이터클래스를 초기화하기위한 함수
private fun initSong(){
//MainActivity에서 보낸데이터 받음
//만약 title값과 singer값이 넘어왔으면, getExtra를 사용해서 받아옴
if(intent.hasExtra("title") && intent.hasExtra("singer")){
song = Song(
intent.getStringExtra("title")!!,
intent.getStringExtra("singer")!!,
intent.getIntExtra("second", 0),
intent.getIntExtra("playTime",0),
intent.getBooleanExtra("isPlaying", false)
)
}
}
// SongActivity화면에 받아와서 초기화된 Song에 대한 정보를 렌더링해주는 함수
private fun setPlayer(song : Song){
//MainActivity에서 보낸데이터 받아서, 제목과 가수의 이름을 바꿔줌
binding.songMusicTitleTv.text = intent.getStringExtra("title")!!
binding.songSingerNameTv.text = intent.getStringExtra("singer")!!
binding.songStartTimeTv.text = String.format("%02d:%02d", song.second / 60, song.second % 60)
binding.songEndTimeTv.text = String.format("%02d:%02d", song.playTime / 60, song.playTime % 60)
binding.songProgressSb.progress = (song.second * 1000 / song.playTime)
setPlayerStatus(song.isPlaying)
}
//initSong,setPlayer 함수 데이터 받아오기
initSong()
setPlayer(song)
# Therad
시간을 세는작업을 무한루프로 구현할것이기 때문에 Timer를 위한 Thread를 생성해줘야한다
class SongActivity : AppCompatActivity(){
lateinit var binding : ActivitySongBinding
//Song 데이터클래스를 초기화하기위해 전역변수 선언
lateinit var song: Song
lateinit var timer : Timer
private fun startTimer(){
// song의 총재생시간, 재생중 의 여부를 생성자의 입력으로 받음
timer = Timer(song.playTime, song.isPlaying)
timer.start()
}
//Thread를 사용해서 노래가 재생되면 seakbar와 텍스트의 값이 바뀌도록
//시간이 지남에따라 seakbar와 타이머 텍스트의 값을 바꿔줘야하기 때문에 inner class로 생성
//보여주고자 하는 노래가 총 몇초인지, 지금 노래가 재생중인지
inner class Timer(private val playTime : Int, var isPlaying: Boolean = true) : Thread(){
//노래의 진행시간을 second와 mills로 나눠서 받아옴
private var second : Int = 0
private var mills : Float = 0F
//해당 스레드가 실행할 코드작성 (run함수내에 작성된코드는 순차적으로 실행)
override fun run() {
super.run()
// try-catch문에서 interrupt를 사용해서 thread를 멈추고, 오류가 발생했을때 특정명령을 실행하도록함
try {
//Timer는 계속 재생되어야하므로 when(true)를 사용해서 반복시켜줌 (무한루프)
//second >= playTime일때 탈출하도록 설정하여, 노래의 총재생시간동안만 스레드가 실행되도록
while(true) {
if(second >= playTime) {
break
}
// 0.2초 대기
while (!isPlaying) {
sleep(200)
}
// isPlaying이 true일때만(노래가 현재재생중일때만) ,50ms마다 프로그레스바를 슬라이드함 (즉, 초당 20번의 slide를 진행해서 자연스러운 슬라이딩효과줌)
if(isPlaying) {
sleep(50)
mills += 50
//progress바
//mills는 ms단위이고, playTime은 초단위 -> playTime에 1000을 곱해야함(근데 여기서는 백분율이아닌 십만분율을 사용하고있기때문에 100곱함)
runOnUiThread{
binding.songProgressSb.progress = ((mills / playTime)*100).toInt()
}
//진행시간 타이머 (mills = 1000 = 1초)
//1초가 지날때마다 second(현재재생시간)을 1씩 증가시키고, songStartTimeTv의 텍스트 갱신
if (mills % 1000 == 0F){
runOnUiThread {
binding.songStartTimeTv.text = String.format("%02d:%02d", second / 60, second % 60)
}
second ++
}
}
}
}catch (e: InterruptedException){
Log.d("SongActivity", "쓰레드가 죽었습니다 ${e.message}")
}
}
}
//activity파괴될때 호출되는 onDestroy함수
override fun onDestroy() {
super.onDestroy()
//thread 종료
timer.interrupt()
}
SongActivity.kt
마지막으로 Activity가 파괴될때 호출되는 onDestroy함수를 추가한다
최종적으로 이렇게 작동하는것을 볼수있다
'Android Project' 카테고리의 다른 글
[Android/Kotlin] FLO앱 클론코딩(4) - 생명주기 (0) | 2024.01.05 |
---|---|
[Android/Kotlin] FLO앱 클론코딩(3) - Splash화면 (0) | 2024.01.05 |
[Android/Kotlin] FLO앱 클론코딩(1) (0) | 2024.01.05 |
[Android/Kotlin] 퀴즈앱(2) (0) | 2023.12.15 |
[Android/Kotlin] 드로잉앱(1) (0) | 2023.12.13 |