本文实例为大家分享了Android实现简单音乐播放器的具体代码,供大家参考,具体内容如下
1.制作一个简易的音乐播放器
使用软件:Android studio + jdk1.8 + Gradle6.5(其他版本也可以)
2.activity_main.xml文件(主页面的编写)
先看一下示意图再来排版(音乐板块的模型看的是某云)
分3个部分来看,第一个是音乐的,就是Sky_High、No Copyright Sounds和那个圆形的可以转动的图标。
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@mipmap/music_background" /> //这里是配置背景的,就是后面的青蓝色板块
<TextView
android:id="@+id/tv_song_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:gravity="center_horizontal"
android:text="Sky_High"
android:textAlignment="center"
android:textSize="24sp" /> //这是第一行Sky_High的
<TextView
android:id="@+id/tv_song_singer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_song_name"
android:gravity="center_horizontal"
android:text="No Copyright Sounds"
android:textAlignment="center"
android:textSize="18sp" /> //这是第二行No Copyright Sounds
<ImageView
android:id="@+id/iv_disk"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_below="@id/tv_song_singer"
android:layout_centerHorizontal="true"
android:layout_marginTop="32dp"
android:src="@mipmap/id3_artwork" /> //圆球图片
<TextView
android:id="@+id/tv_lyric_previous"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/iv_disk"
android:layout_marginTop="16dp"
android:gravity="center_horizontal"
android:text="---"
android:textAlignment="center" /> //这是为了方便“此音乐为纯音乐,请欣赏”这里的排版大小来加的,可以删除掉
<TextView
android:id="@+id/tv_lyric_current"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_lyric_previous"
android:layout_marginTop="16dp"
android:gravity="center_horizontal"
android:text="此音乐为纯音乐,请欣赏"
android:textAlignment="center"
android:textSize="20dp" /> //“此音乐为纯音乐,请欣赏”这里是用来放歌词的
<TextView
android:id="@+id/tv_lyric_next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_lyric_current"
android:layout_marginTop="16dp"
android:gravity="center_horizontal"
android:text="---"
android:textAlignment="center" /> //这是为了方便“此音乐为纯音乐,请欣赏”这里的排版大小来加的,可以删除掉
第二部分是用来显示音乐播放进度的SeekBar
<RelativeLayout
android:id="@+id/rl_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_lyric_next"
android:layout_marginTop="32dp">
<androidx.appcompat.widget.AppCompatSeekBar //这里一般看版本的,有点版本直接seekBar就行了,我的版本较低
android:id="@+id/sb_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_progress_current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/sb_progress"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:text="0:00" /> //这是两个定点,这个定点表示声音起始点
<TextView
android:id="@+id/tv_progress_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/sb_progress"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:text="0:00" /> //这是两个定点,这个定点表示声音终点
</RelativeLayout>
第三部分是音乐的暂停、开始、继续、前一首和后一首的选择。
这一部分可能就是排版比较烦,耐心点还是可以弄好的,调参可能费点时间。
<RelativeLayout
android:id="@+id/rl_control"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="32dp">
<ImageButton
android:id="@+id/btn_prev"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_centerHorizontal="true"
android:layout_toStartOf="@id/btn_play_pause"
android:layout_toLeftOf="@id/btn_play_pause"
android:scaleType="fitCenter"
android:src="@mipmap/id3_icon_prev_d" />
<ImageButton
android:id="@+id/btn_play_pause"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_centerHorizontal="true"
android:scaleType="fitCenter"
android:src="@mipmap/id3_button_pause_n" />
<ImageButton
android:id="@+id/btn_next"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_centerHorizontal="true"
android:layout_toEndOf="@id/btn_play_pause"
android:layout_toRightOf="@id/btn_play_pause"
android:scaleType="fitCenter"
android:src="@mipmap/id3_icon_next_d" />
</RelativeLayout>
下面一部分是MainActivity.java的编写
这一部分关键在于球型图的转动、seekbar的运行和音乐的暂停播放逻辑关系等等
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
import android.animation.ObjectAnimator;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private TextView songName, singerName;
private ImageView diskImage;
private TextView lyricPrev, lyricCurrent, lyricNext;
private SeekBar musicProgress;
private TextView currentTime, totalTime;
private ImageButton prevBtn, playPauseBtn, nextBtn;
private ObjectAnimator animator;
private MediaPlayer player;
private int currentPlaying = 0; //用作ArrayList下表,当前播放的歌曲、
private ArrayList<Integer> playList = new ArrayList<>();
private boolean isPausing, isPlaying; //音乐暂停状态,音乐第一次播放之后变为true
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
preparePlayList();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
if (isPlaying) {
updateTimer();
}
}
};
new Timer().scheduleAtFixedRate(timerTask, 0, 500);
}
void init() {
songName = findViewById(R.id.tv_song_name);
singerName = findViewById(R.id.tv_song_singer);
diskImage = findViewById(R.id.iv_disk);
lyricPrev = findViewById(R.id.tv_lyric_previous);
lyricCurrent = findViewById(R.id.tv_lyric_current);
lyricNext = findViewById(R.id.tv_lyric_next);
musicProgress = findViewById(R.id.sb_progress);
currentTime = findViewById(R.id.tv_progress_current);
totalTime = findViewById(R.id.tv_progress_total);
prevBtn = findViewById(R.id.btn_prev);
playPauseBtn = findViewById(R.id.btn_play_pause);
nextBtn = findViewById(R.id.btn_next);
View.OnClickListener onClick = new OnClickControl();
prevBtn.setOnClickListener(onClick);
playPauseBtn.setOnClickListener(onClick);
nextBtn.setOnClickListener(onClick);
OnSeekBarChangeControl onSbChange = new OnSeekBarChangeControl();
musicProgress.setOnSeekBarChangeListener(onSbChange);
animator = ObjectAnimator.ofFloat(diskImage, "rotation", 0, 360.0F); //初始化状态
animator.setDuration(2000); //状态时长,10秒
animator.setInterpolator(new LinearInterpolator()); //时间函数,有很多类型
animator.setRepeatCount(-1); // 一直旋转
}
private void preparePlayList() {
Field[] field = R.raw.class.getFields();
for (int count = 0; count < field.length; count++) {
Log.i("Raw Asset", field[count].getName());
try {
int resId = field[count].getInt(field[count]);
playList.add(resId);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
private void prepareMedia() {
if (isPlaying) {
player.stop();
player.reset();
}
player = MediaPlayer.create(getApplicationContext(), playList.get(currentPlaying));
int musicDuration = player.getDuration();
musicProgress.setMax(musicDuration);
int sec = musicDuration / 1000;
int min = sec / 60;
sec -= min * 60;
String musicTime = String.format("%02d:%02d", min, sec);
totalTime.setText(musicTime);
player.start();
}
private void updateTimer() {
runOnUiThread(() -> {
int currentMs = player.getCurrentPosition();
int sec = currentMs / 1000;
int min = sec / 60;
sec -= min * 60;
String time = String.format("%02d:%02d", min, sec);
musicProgress.setProgress(currentMs);
currentTime.setText(time);
});
}
//这一部分很重要,对于初学者来说,一定要搞清楚这三个按钮之间的逻辑关系,因为要判断如果音乐暂停了,是执行哪个线程,跳到哪个图标上去。怎么样继续运行接下来的音乐,我这里加了日志文件,可以判断一下哪一步出错了。
private class OnClickControl implements View.OnClickListener {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_prev:
//重播
Log.i("INFO", "onClick:重播按钮被点击!");
playPauseBtn.setImageResource(R.mipmap.id3_button_pause_n); //切换成暂停键
animator.start();
if (!player.isPlaying()) {
currentPlaying = --currentPlaying % playList.size();
}
prepareMedia();
isPausing = false;
isPlaying = true;
break;
case R.id.btn_play_pause:
//开始暂停
Log.i("INFO", "onClick:开始暂停按钮被点击!");
if (!isPausing && !isPlaying) { //暂停状态,且从未被播放
//开始播放
playPauseBtn.setImageResource(R.mipmap.id3_button_pause_n); //切换成暂停键
animator.start();
prepareMedia();
isPlaying = true;
} else if (!isPausing && isPlaying) { //暂停状态,且被播放过一次
//继续播放
playPauseBtn.setImageResource(R.mipmap.id3_button_pause_n);//切换成暂停键
animator.resume();
player.start();
} else { //播放状态
//暂停播放
playPauseBtn.setImageResource(R.mipmap.id3_button_play_p);//切换成播放键
animator.pause();
player.pause();
}
isPausing = !isPausing; //切换歌曲
break;
case R.id.btn_next:
Log.i("INFO", "onClick:重播按钮被点击!");
//切歌
playPauseBtn.setImageResource(R.mipmap.id3_button_pause_n); // 切换成暂停键
currentPlaying = ++currentPlaying % playList.size();
prepareMedia();
animator.start();
isPausing = false;
isPlaying = true;
break;
default:
Log.i("INFO", "onClick:按钮被点击了,但是有BUG");
//有BUG了
}
}
}
private class OnSeekBarChangeControl implements SeekBar.OnSeekBarChangeListener {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
player.seekTo(progress);
}
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
player.pause();
animator.pause();
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
player.start();
if (seekBar.getProgress() < 10) {
animator.start();
} else {
animator.resume();
}
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。