[Android] 음악 재생 플레이어 만들기
몇 가지 기능이 있는 음악 재생 플레이어를 만들어보자.
소스코드
<Java 소스코드>
package kr.ac.cnu.computer.seekbar;
import android.media.MediaPlayer;
import android.view.View;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
MediaPlayer player;
TextView titleView;
ImageButton playButton;
SeekBar seekBar;
boolean checkplay = false;
boolean firstcheckplay = false;
class t1 extends Thread{
public void run(){
while(checkplay){
seekBar.setProgress(player.getCurrentPosition());
}
}
} // 쓰레드를 이용하기 위해 쓰레드 클래스를 생성하자
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 음악 제목
titleView = findViewById(R.id.titleView);
// 음악 탐색바
seekBar = findViewById(R.id.seekBar);
// Play 버튼. 다시 누르면 Pause 버튼으로 변경
playButton = findViewById(R.id.playButton);
// MediaPlayer 음악 재생 관련 객체
player = MediaPlayer.create(this, R.raw.old_pop);
seekBar.setMax(player.getDuration());
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean check) {
if (check) {
player.seekTo(progress);
}
if(seekBar.getMax()==progress){ //끌어서 마지막으로 놓으면 멈추게 해야 한다.
checkplay = false;
player.stop();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekbar) {
checkplay = false;
player.pause();
}
@Override
public void onStopTrackingTouch(SeekBar seekbar) {
if(firstcheckplay==true){
checkplay = true;
player.seekTo(seekBar.getProgress());
player.start();
new t1().start();
}else{
checkplay = true;
player.seekTo(seekBar.getProgress());
}
}
});
// 여기까지 seekbar 구현
}// oncreate의 끝
/**
* 이 버튼을 누르면 현재 위치에서 5초 뒤로 이동한다.
* @param view
*/
public void rewindAction(View view) {
player.seekTo(player.getCurrentPosition() - 5000);
seekBar.setProgress(player.getCurrentPosition());// 일시정지 상태에서 이 버튼 눌러도 seekbar가 상태를 반영하게 함.
}
////////////////////////////////////////////////////////////////////////////
/**
* 재생 중이 아니면 음악을 재생하고, 재생중이면 음악을 중지한다.
* @param view
*/
public void playAction(View view) {
if (!player.isPlaying()) { // 진행중이 아닐 때
player.start();
playButton.setImageResource(R.drawable.ic_pause);
new t1().start();
checkplay = true; // seekbar를 그릴 쓰레드를 반복해야함
firstcheckplay = true; // 정지상태에서 씨크바 드래그드롭으로 조작 시 내가 의도하지 않은 결과가 나온다.
// (시작 정지 버튼이 꼬이게 됨) firstcheckplay를 도입해서 그걸 해결했음.
} else { // 진행중일 때
player.pause();
playButton.setImageResource(R.drawable.ic_play_arrow);
checkplay = false; // seekbar 쓰레드도 정지함
firstcheckplay = false; // 정지상태에서 씨크바 드래그드롭으로 조작 시 내가 의도하지 않은 결과가 나온다.
// (시작 정지 버튼이 꼬이게 됨) firstcheckplay를 도입해서 그걸 해결했음.
}
}
//////////////////////////////////////////////////////////////////
/**
* 이 버튼을 누르면 현재 위치에서 5초 앞으로 이동한다.
* @param view
*/
public void forwardAction(View view) {
player.seekTo(player.getCurrentPosition() + 5000);
seekBar.setProgress(player.getCurrentPosition());// 일시정지 상태에서 이 버튼 눌러도 seekbar가 상태를 반영하게 함.
}
public void onBackPressed(){// 앱을 나갔을 때 음악도 멈춰야 함
onDestroy();
}
}
<xml 소스코드>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="36sp"
android:text="Old Pop"
android:textStyle="bold"
android:gravity="center"
android:id="@+id/titleView"
app:layout_constraintBottom_toTopOf="@id/albumImage"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" android:singleLine="true"/>
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/honey_honey"
android:id="@+id/albumImage"
android:adjustViewBounds="true"
app:layout_constraintBottom_toTopOf="@id/seekBar"
app:layout_constraintTop_toBottomOf="@id/titleView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<SeekBar android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/seekBar"
app:layout_constraintTop_toBottomOf="@id/albumImage"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/playButton"/>
<ImageButton android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/rewindButton"
android:src="@drawable/ic_fast_rewind"
android:onClick="rewindAction"
app:layout_constraintTop_toBottomOf="@id/seekBar"
app:layout_constraintEnd_toStartOf="@id/playButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<ImageButton android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/playButton"
android:src="@drawable/ic_play_arrow"
android:onClick="playAction"
app:layout_constraintTop_toBottomOf="@id/seekBar"
app:layout_constraintStart_toEndOf="@id/rewindButton"
app:layout_constraintEnd_toStartOf="@id/forwardButton"
app:layout_constraintBottom_toBottomOf="parent"/>
<ImageButton android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/forwardButton"
android:src="@drawable/ic_fast_forward"
android:onClick="forwardAction"
app:layout_constraintTop_toBottomOf="@id/seekBar"
app:layout_constraintStart_toEndOf="@id/playButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<설명>
Thread와 SeekBar를 이용해 음악을 재생하는 플레이어 앱을 만들었다.
MediaPlayer player;
TextView titleView;
ImageButton playButton;
SeekBar seekBar;
boolean checkplay = false;
boolean firstcheckplay = false;
class t1 extends Thread{
public void run(){
while(checkplay){
seekBar.setProgress(player.getCurrentPosition());
}
}
} // 쓰레드를 이용하기 위해 쓰레드 클래스를 생성하자
재생 여부를 확인하는 boolean 타입의 변수들과 SeekBar를 담당하는 쓰레드이다.
쓰레드는 checkplay가 참일 경우. 즉, 음악이 재생되고 있을 경우에만 동작하도록 만들었고, SeekBar의 진행 값은 현재 노래의 길이에 맞춰 설정하도록 했다.
seekBar.setMax(player.getDuration());
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean check) {
if (check) {
player.seekTo(progress);
}
if(seekBar.getMax()==progress){ //끌어서 마지막으로 놓으면 멈추게 해야 한다.
checkplay = false;
player.stop();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekbar) {
checkplay = false;
player.pause();
}
@Override
public void onStopTrackingTouch(SeekBar seekbar) {
if(firstcheckplay==true){
checkplay = true;
player.seekTo(seekBar.getProgress());
player.start();
new t1().start();
}else{
checkplay = true;
player.seekTo(seekBar.getProgress());
}
}
});
다음은 seekBar의 기본 설정과 seekbar의 값이 변경됐을 때 이벤트리스너를 활용해 동작에 따른 행동을 처리해줬다.
seekbar를 드래그하고 드롭하는 동작을 수행할 때 드래그하고있는 과정에서는 seekbar의 진행상황에 맞춰 노래의 진행상황을 설정하고 노래를 일시정지시켰다. checkplay를 false로 바꿔 노래가 일시정지되는동안 Seekbar를 담당하는 쓰레드도 일시정지시켰다.
드래그를 시작할 때와 끝마칠 때를 처리해줘야 한다.
앱을 만들고 실행하다 보니, 음악을 일시정지한 상태에서 seekbar를 통해 임의의 위치로 노래를 재생시켰는데, 이 경우 자동으로 일시정지가 풀리는 경우가 발생했다. 이를 방지하기 위해 일시정지 도중에 seekbar를 조작했을 때는 일시정지를 유지하고 일시정지가 아닐 때 seekbar를 조작했을 때는 재생을 유지하도록 코드를 작성했다. 이 과정에서 firstplaycheck 변수가 사용됐다.
public void rewindAction(View view) {
player.seekTo(player.getCurrentPosition() - 5000);
seekBar.setProgress(player.getCurrentPosition());// 일시정지 상태에서 이 버튼 눌러도seekbar가 상태를 반영하게 함.
}
뒤로가기 버튼을 눌렀을 때이다. 이 때 음악 뿐만 아니라 seekbar에도 상태가 반영되도록 코드를 작성했다. (앞으로 가기 버튼도 마찬가지)
public void playAction(View view) {
if (!player.isPlaying()) { // 진행중이 아닐 때
player.start();
playButton.setImageResource(R.drawable.ic_pause);
new t1().start();
checkplay = true; // seekbar를 그릴 쓰레드를 반복해야함
firstcheckplay = true; // 정지상태에서 씨크바 드래그드롭으로 조작 시 내가 의도하지 않은 결과가 나온다.
// (시작 정지 버튼이 꼬이게 됨) firstcheckplay를 도입해서 그걸 해결했음.
} else { // 진행중일 때
player.pause();
playButton.setImageResource(R.drawable.ic_play_arrow);
checkplay = false; // seekbar 쓰레드도 정지함
firstcheckplay = false; // 정지상태에서 씨크바 드래그드롭으로 조작 시 내가 의도하지 않은 결과가 나온다.
// (시작 정지 버튼이 꼬이게 됨) firstcheckplay를 도입해서 그걸 해결했음.
}
}
음악이 재생 중이 아닐 때는 플레이 버튼으로 쓰레드와 음악을 재생시킬 수 있다. firstcheckplay는 이전에 설명했으니 넘어가자.
재생 중일 때는 플레이 버튼이 일시정지버튼기능을 한다.
public void onBackPressed(){// 앱을 나갔을 때 음악도 멈춰야 함
onDestroy();
}
핸드폰의 뒤로가기 버튼으로 나갔을 때 음악도 종료하도록 만들었다.
'Mobile > Android' 카테고리의 다른 글
[Android] 내용 제공자 (Content Provider) (0) | 2021.11.29 |
---|---|
[Android] 모바일 데이터베이스 (0) | 2021.11.21 |
[Android] 리스트 보여주기 (0) | 2021.11.21 |
[Android] 쓰레드와 핸들러 (0) | 2021.11.12 |
[Android] 서비스와 브로드캐스트 수신자 (0) | 2021.11.06 |
댓글
이 글 공유하기
다른 글
-
[Android] 내용 제공자 (Content Provider)
[Android] 내용 제공자 (Content Provider)
2021.11.29 -
[Android] 모바일 데이터베이스
[Android] 모바일 데이터베이스
2021.11.21 -
[Android] 리스트 보여주기
[Android] 리스트 보여주기
2021.11.21 -
[Android] 쓰레드와 핸들러
[Android] 쓰레드와 핸들러
2021.11.12