给定部分完成的MusicPlayer项目,实现其中未完成的service部分:
1、创建MusicService类,通过service组件实现后台播放音乐的功能;
2、在MainActivity中通过ServiceConnection连接MusicService,实现对音乐播放的控制;
3、使用Handler机制在MainActivity和MusicService之间进行通信。
目前已有代码:
相关的资源文件,可自行寻找
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/music_bg"
android:gravity="center"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="160dp"
tools:ignore="UselessParent">
<RelativeLayout
android:id="@+id/rl_title"
android:layout_width="300dp"
android:layout_height="70dp"
android:layout_centerHorizontal="true"
android:background="@drawable/title_bg"
android:gravity="center_horizontal"
android:paddingStart="80dp"
tools:ignore="RtlSymmetry">
<TextView
android:id="@+id/tv_music_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/song_name"
android:textSize="12sp"
android:textStyle="bold"
android:textColor="@android:color/black"/>
<TextView
android:layout_marginTop="4dp"
android:id="@+id/tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_music_title"
android:layout_alignStart="@id/tv_music_title"
android:text="@string/pop_music"
android:textSize="10sp"
tools:ignore="SmallSp" />
<SeekBar
android:id="@+id/sb"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_below="@id/rl_time"
android:layout_alignParentBottom="true"
android:thumb="@null" />
<RelativeLayout
android:layout_marginTop="4dp"
android:id="@+id/rl_time"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_below="@id/tv_type">
<TextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/zero_time"
android:textSize="10sp"
tools:ignore="SmallSp" />
<TextView
android:id="@+id/tv_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:text="@string/zero_time"
android:textSize="10sp"
tools:ignore="RelativeOverlap,SmallSp" />
RelativeLayout>
RelativeLayout>
<LinearLayout
android:layout_width="340dp"
android:layout_height="90dp"
android:layout_below="@id/rl_title"
android:layout_centerHorizontal="true"
android:background="@drawable/btn_bg"
android:gravity="center_vertical"
android:paddingStart="120dp"
android:paddingEnd="10dp">
<Button
android:id="@+id/btn_play"
android:layout_width="0dp"
android:layout_height="25dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/btn_bg_selector"
android:text="@string/play"
android:textSize="10sp"
tools:ignore="ButtonStyle,SmallSp" />
<Button
android:id="@+id/btn_pause"
android:layout_width="0dp"
android:layout_height="25dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/btn_bg_selector"
android:text="@string/pause"
android:textSize="10sp"
tools:ignore="ButtonStyle,SmallSp" />
<Button
android:id="@+id/btn_continue_play"
android:layout_width="0dp"
android:layout_height="25dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/btn_bg_selector"
android:text="@string/cont"
android:textSize="10sp"
tools:ignore="ButtonStyle,SmallSp" />
<Button
android:id="@+id/btn_exit"
android:layout_width="0dp"
android:layout_height="25dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/btn_bg_selector"
android:text="@string/exit"
android:textSize="10sp"
tools:ignore="ButtonStyle,SmallSp" />
LinearLayout>
<ImageView
android:id="@+id/iv_music"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerVertical="true"
android:layout_marginStart="35dp"
android:layout_marginBottom="50dp"
android:src="@drawable/img_music"
android:contentDescription="@string/iv" />
RelativeLayout>
LinearLayout>
MainActivity.java
package cn.itcast.musicplayer;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static SeekBar sb;
private static TextView tv_progress, tv_total;
private ObjectAnimator animator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
tv_progress = findViewById(R.id.tv_progress);
tv_total = findViewById(R.id.tv_total);
sb = findViewById(R.id.sb);
findViewById(R.id.btn_play).setOnClickListener(this);
findViewById(R.id.btn_pause).setOnClickListener(this);
findViewById(R.id.btn_continue_play).setOnClickListener(this);
findViewById(R.id.btn_exit).setOnClickListener(this);
//为滑动条添加事件监听
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean
fromUser) { //滑动条进度改变时,会调用此方法
if (progress == seekBar.getMax()) { //当滑动条滑到末端时,结束动画
animator.pause(); //停止播放动画
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {//滑动条开始滑动时调用
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) { //滑动条停止滑动时调用
//根据拖动的进度改变音乐播放进度
int progress = seekBar.getProgress();//获取seekBar的进度
}
});
ImageView iv_music = findViewById(R.id.iv_music);
animator = ObjectAnimator.ofFloat(iv_music, "rotation", 0f, 360.0f);
animator.setDuration(10000); //动画旋转一周的时间为10秒
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(-1); //-1表示设置动画无限循环
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_play: //播放按钮点击事件
animator.start(); //播放动画
break;
case R.id.btn_pause: //暂停按钮点击事件
animator.pause(); //暂停播放动画
break;
case R.id.btn_continue_play: //继续播放按钮点击事件
animator.start(); //播放动画
break;
case R.id.btn_exit: //退出按钮点击事件
finish(); //关闭音乐播放界面
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//解绑服务
}
}
当前已经有一个用户界面,其中包括了播放、暂停、继续播放和退出按钮,以及一个旋转动画效果。现在,我们需要将MusicService与MainActivity连接起来,以实现音乐的播放和控制功能。
步骤 1: 创建 MusicService 类
首先,你需要创建一个名为 MusicService
的类,该类将负责处理音乐播放和与 MainActivity 之间的通信。
package cn.itcast.musicplayer;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
public class MusicService extends Service {
private MediaPlayer mediaPlayer;
public MusicService() {
}
@Override
public IBinder onBind(Intent intent) {
return new MusicBinder();
}
public class MusicBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
// 在这里设置音乐资源,例如 mediaPlayer.setDataSource(your_music_uri);
mediaPlayer = MediaPlayer.create(this, R.raw.music); // 加载音乐资源
}
// 添加播放音乐的方法
public void playMusic() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
// 添加暂停音乐的方法
public void pauseMusic() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
// 添加继续播放音乐的方法
public void continueMusic() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
@Override
public void onDestroy() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
super.onDestroy();
}
}
相关变量描述:
MusicService
是一个 Android 服务类,用于处理音乐播放相关的功能。
mediaPlayer
是用于播放音乐的 MediaPlayer 对象,它负责加载音乐资源、播放、暂停和继续播放音乐。
MusicBinder
内部类继承自 Binder,用于绑定服务与其他组件之间的通信。
onBind
方法用于返回 MusicBinder
对象,以便其他组件可以与服务进行绑定。
onCreate
方法在服务创建时被调用,它初始化了 mediaPlayer
并加载音乐资源。在这个示例中,音乐资源是从 R.raw.music
中加载的。
playMusic
方法用于播放音乐,如果音乐未在播放状态,则调用 mediaPlayer.start()
来开始播放。
pauseMusic
方法用于暂停音乐,如果音乐正在播放,则调用 mediaPlayer.pause()
来暂停。
continueMusic
方法用于继续播放音乐,如果音乐已暂停,则调用 mediaPlayer.start()
来继续播放。
onDestroy
方法在服务销毁时被调用,它释放了 mediaPlayer
对象的资源,确保不会产生内存泄漏。
服务允许其他组件与其绑定,以控制音乐的播放、暂停和继续播放;载了一个音乐资源(在这个示例中是 R.raw.music
),并使用 MediaPlayer
对象进行音乐播放
在AndroidManifest.xml中注册MusicService(检查)
确保在AndroidManifest.xml文件中注册MusicService,以便应用能够正常启动该服务。
一般在我们创建service文件后,会自动进行注册的
<service android:name=".MusicService" />
步骤 2: 在 MainActivity 中连接 MusicService
在 MainActivity
中,添加代码来连接 MusicService
并控制音乐的播放、暂停和继续。
private MusicService musicService;
private boolean isBound = false;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
musicService = binder.getService();
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MusicService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (isBound) {
unbindService(serviceConnection);
isBound = false;
}
}
步骤 3: 在 MainActivity 中调用 MusicService 的方法
在 onClick
方法中调用 MusicService
的方法来控制音乐的播放、暂停和继续。
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_play: // 播放按钮点击事件
if (isBound) {
musicService.playMusic();
}
animator.start(); // 播放动画
break;
case R.id.btn_pause: // 暂停按钮点击事件
if (isBound) {
musicService.pauseMusic();
}
animator.pause(); // 暂停播放动画
break;
case R.id.btn_continue_play: // 继续播放按钮点击事件
if (isBound) {
musicService.continueMusic();
}
animator.start(); // 播放动画
break;
case R.id.btn_exit: // 退出按钮点击事件
finish(); // 关闭音乐播放界面
break;
}
}
当前,我们就已经初步完成了简单音乐播放器的播放、暂停、继续、退出功能;
你可以尝试此时运行项目测试效果!
步骤 4: 修改MusicService(以实现通信更新UI)
添加获取相关信息函数
// 获取音乐总时长
public int getTotalDuration() {
return mediaPlayer.getDuration();
}
// 获取音乐当前播放进度
public int getCurrentPosition() {
return mediaPlayer.getCurrentPosition();
}
// 设置音乐播放进度
public void seekTo(int position) {
mediaPlayer.seekTo(position);
}
// 更新UI,发送消息给MainActivity
private void updateUI(int progress, int totalDuration) {
if (handler != null) {
Message message = Message.obtain(handler, UPDATE_UI, progress, totalDuration);
handler.sendMessage(message);
}
}
@Override
public void onCreate() {
super.onCreate();
mediaPlayer = MediaPlayer.create(this, R.raw.music); // 加载音乐资源
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// 音乐播放完成时的处理
}
});
// 定时发送消息以更新UI
Runnable runnable = new Runnable() {
@Override
public void run() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
int progress = mediaPlayer.getCurrentPosition();
int totalDuration = mediaPlayer.getDuration();
updateUI(progress, totalDuration);
}
handler.postDelayed(this, DELAY_MILLIS);
}
};
handler.postDelayed(runnable, DELAY_MILLIS);
}
这段代码是为 MusicService
添加了一些重要的功能,以实现与 MainActivity
之间的通信并更新UI。以下是代码的描述:
getTotalDuration
函数用于获取音乐的总时长。它通过 mediaPlayer.getDuration()
方法获取音乐的总时长,然后返回该值。
getCurrentPosition
函数用于获取音乐的当前播放进度。通过 mediaPlayer.getCurrentPosition()
方法获取音乐的当前播放进度,然后返回该值。
seekTo
函数用于设置音乐的播放进度。接受一个整数参数 position
,表示要设置的音乐播放进度,并使用 mediaPlayer.seekTo(position)
方法来实现进度的跳转。
updateUI
函数用于发送消息给 MainActivity
,以便更新UI元素。它接受两个参数,分别是当前播放进度 progress
和音乐总时长 totalDuration
。它创建一个 Message
对象,并通过 handler.sendMessage(message)
发送消息给 MainActivity
,以便更新UI元素,比如进度条和文本。
在 onCreate
方法中,定时发送消息以更新UI。通过一个 Runnable
定时任务,在其中获取当前播放进度和音乐总时长,然后调用 updateUI
函数发送消息给 MainActivity
,以实现不断更新UI元素的目的。
这些函数和逻辑使 MusicService
能够与 MainActivity
进行通信,传递音乐播放进度和总时长,以便 MainActivity
能够更新UI元素,提供用户友好的音乐播放体验。
步骤 5: 修改MainActivity(以实现通信更新UI)
在MusicService中获取音乐总时长,并在MainActivity中更新tv_total和进度条的位置,以及格式化音乐的总时长和进度。
private static final int UPDATE_UI = 1;
public final static Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == UPDATE_UI) {
int progress = msg.arg1;
int totalDuration = msg.arg2;
updateUI(progress, totalDuration);
}
}
};
public static void updateUI(int progress, int totalDuration) {
sb.setProgress(progress);
tv_progress.setText(formatDuration(progress));
// 更新左侧显示的总时间
tv_total.setText(formatDuration(totalDuration));
}
// 辅助方法来更新进度
private void updateProgress(int progress) {
tv_progress.setText(formatDuration(progress));
}
// 辅助方法来格式化音乐时长
private static String formatDuration(int duration) {
int minutes = (duration / 1000) / 60;
int seconds = (duration / 1000) % 60;
return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
}
// 添加方法来更新总时长
private void updateTotalDuration(int duration) {
tv_total.setText(formatDuration(duration));
sb.setMax(duration);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
musicService = binder.getService();
isBound = true;
// 获取音乐总时长并更新UI
int totalDuration = musicService.getTotalDuration();
updateTotalDuration(totalDuration);
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
private void init() {
// 初始化控件和按钮点击事件监听
tv_progress = findViewById(R.id.tv_progress);
tv_total = findViewById(R.id.tv_total);
sb = findViewById(R.id.sb);
// ...
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (progress == seekBar.getMax()) {
animator.pause();
}
updateProgress(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// 更新音乐播放进度
int progress = seekBar.getProgress();
musicService.seekTo(progress); // 添加 seekTo 方法用于定位音乐进度
}
});
// ...
这段代码是为 MainActivity
添加了与 MusicService
之间的通信,以便实现音乐播放进度的动态更新和音乐总时长的显示。以下是代码的描述:
在 MainActivity
中定义了一个 handler
,这是一个静态的 Handler
对象,它用于处理从 MusicService
发送的消息,以便更新UI元素。通过 UPDATE_UI
常量来标识消息类型。
updateUI
函数是用于更新UI元素的核心方法。接受两个参数,分别是当前播放进度 progress
和音乐总时长 totalDuration
。在这个方法中,进度条的位置会被设置为当前播放进度,左侧的文本 tv_progress
会被更新为格式化后的播放进度,而左侧的总时长文本 tv_total
会被更新为格式化后的音乐总时长。
updateProgress
方法是一个辅助方法,用于更新播放进度。接受一个参数 progress
,并更新左侧的文本 tv_progress
为格式化后的播放进度。
formatDuration
方法是一个辅助方法,用于格式化音乐时长。接受一个整数 duration
,表示音乐的时长(以毫秒为单位),然后将其格式化为分:秒的形式。
updateTotalDuration
方法用于更新总时长。它接受一个参数 duration
,表示音乐的总时长,并更新左侧的总时长文本 tv_total
为格式化后的音乐总时长,并设置进度条的最大值为音乐的总时长。
在 serviceConnection
中,当 MusicService
与 MainActivity
连接成功后,会获取音乐的总时长并调用 updateTotalDuration
方法来更新UI元素。
在 sb
(SeekBar)的事件监听器中,通过 onProgressChanged
方法,当进度条的进度发生变化时,会调用 updateProgress
方法来更新左侧的播放进度文本。在 onStopTrackingTouch
方法中,当用户拖动进度条时,会调用 musicService.seekTo(progress)
方法来定位音乐的进度。
这些代码改动使 MainActivity
能够与 MusicService
协同工作,以实现音乐播放进度的动态更新和音乐总时长的显示。这对于提供用户友好的音乐播放体验至关重要。
步骤 6: 增加音乐结束后的处理细节
对于这些新的问题,我们可以进行以下修改和处理:
MusicService
中添加了一个音乐播放完成回调,以便在音乐结束时暂停动画。这样,用户可以看到音乐已经完成,同时动画不再旋转,提供了明确的视觉指示。如下所示:mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// 音乐播放完成时的处理
animator.pause(); // 停止动画
}
});
tv_progress.setText(formatDuration(getTotalDuration()))
,我们将左侧的时间文本设置为音乐的总时长,以表明音乐已完成 @Override
public void onCreate() {
//……
@Override
public void onCompletion(MediaPlayer mp) {
// 音乐播放完成时的处理
animator.pause(); // 停止动画
tv_progress.setText(formatDuration(getTotalDuration()));
}
});
}
MusicService
中的音乐播放完成回调中,我们使用showToast
函数显示一个短暂的提示消息。这种提醒可以根据你的需求进行扩展,例如,你可以选择显示通知、执行其他操作或添加更多的用户反馈。 private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
@Override
public void onCreate() {
//……
@Override
public void onCompletion(MediaPlayer mp) {
// 音乐播放完成时的处理
animator.pause(); // 停止动画
showToast("音乐已完成"); // 显示音乐播放完成的提示
}
});
}
完整代码
MainActivity.java
package cn.itcast.musicplayer;
import static cn.itcast.musicplayer.MusicService.mediaPlayer;
import android.animation.ObjectAnimator;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Bundle;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Locale;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static SeekBar sb;
public static TextView tv_progress, tv_total;
public static ObjectAnimator animator;
private MusicService musicService;
private boolean isBound = false;
private static final int UPDATE_UI = 1;
// 辅助方法来格式化音乐时长
public static String formatDuration(int duration) {
int minutes = (duration / 1000) / 60;
int seconds = (duration / 1000) % 60;
return String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
}
// 添加方法来更新总时长
private void updateTotalDuration(int duration) {
tv_total.setText(formatDuration(duration));
sb.setMax(duration);
}
// 辅助方法来更新进度
private void updateProgress(int progress) {
tv_progress.setText(formatDuration(progress));
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
musicService = binder.getService();
isBound = true;
// 获取音乐总时长并更新UI
int totalDuration = musicService.getTotalDuration();
updateTotalDuration(totalDuration);
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
public final static Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == UPDATE_UI) {
int progress = msg.arg1;
int totalDuration = msg.arg2;
updateUI(progress, totalDuration);
}
}
};
public static void updateUI(int progress, int totalDuration) {
sb.setProgress(progress);
tv_progress.setText(formatDuration(progress));
tv_total.setText(formatDuration(totalDuration));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
// 初始化控件和按钮点击事件监听
tv_progress = findViewById(R.id.tv_progress);
tv_total = findViewById(R.id.tv_total);
sb = findViewById(R.id.sb);
findViewById(R.id.btn_play).setOnClickListener(this);
findViewById(R.id.btn_pause).setOnClickListener(this);
findViewById(R.id.btn_continue_play).setOnClickListener(this);
findViewById(R.id.btn_exit).setOnClickListener(this);
// ...
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (progress == seekBar.getMax()) {
animator.pause();
}
updateProgress(progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// 更新音乐播放进度
int progress = seekBar.getProgress();
musicService.seekTo(progress); // 添加 seekTo 方法用于定位音乐进度
}
});
// 初始化动画
ImageView iv_music = findViewById(R.id.iv_music);
animator = ObjectAnimator.ofFloat(iv_music, "rotation", 0f, 360.0f);
animator.setDuration(10000); //动画旋转一周的时间为10秒
animator.setInterpolator(new LinearInterpolator());
animator.setRepeatCount(-1); //-1表示设置动画无限循环
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_play:
if (isBound) {
musicService.playMusic();
}
animator.start();
break;
case R.id.btn_pause:
if (isBound) {
musicService.pauseMusic();
}
animator.pause();
break;
case R.id.btn_continue_play:
if (isBound) {
musicService.continueMusic();
}
animator.start();
break;
case R.id.btn_exit:
finish();
break;
}
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MusicService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
//解绑服务
if (isBound) {
unbindService(serviceConnection);
isBound = false;
}
}
}
MusicService.java
package cn.itcast.musicplayer;
import static cn.itcast.musicplayer.MainActivity.formatDuration;
import static cn.itcast.musicplayer.MainActivity.handler;
import static cn.itcast.musicplayer.MainActivity.animator;
import static cn.itcast.musicplayer.MainActivity.tv_progress;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.widget.Toast;
public class MusicService extends Service {
public static MediaPlayer mediaPlayer;
private final IBinder binder = new MusicBinder();
private final int UPDATE_UI = 1;
private final int DELAY_MILLIS = 1000; // 延迟1秒发送消息
public MusicService() {
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public class MusicBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
@Override
public void onCreate() {
super.onCreate();
mediaPlayer = MediaPlayer.create(this, R.raw.music); // 加载音乐资源
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// 音乐播放完成时的处理
animator.pause(); // 停止动画
tv_progress.setText(formatDuration(getTotalDuration()));
showToast("音乐已完成"); // 显示音乐播放完成的提示
}
});
// 定时发送消息以更新UI
Runnable runnable = new Runnable() {
@Override
public void run() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
int progress = mediaPlayer.getCurrentPosition();
int totalDuration = mediaPlayer.getDuration();
updateUI(progress, totalDuration);
}
handler.postDelayed(this, DELAY_MILLIS);
}
};
handler.postDelayed(runnable, DELAY_MILLIS);
}
// 更新UI,发送消息给MainActivity
private void updateUI(int progress, int totalDuration) {
if (handler != null) {
Message message = Message.obtain(handler, UPDATE_UI, progress, totalDuration);
handler.sendMessage(message);
}
}
// 添加播放音乐的方法
public void playMusic() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
// 添加暂停音乐的方法
public void pauseMusic() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
// 添加继续播放音乐的方法
public void continueMusic() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
@Override
public void onDestroy() {
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
super.onDestroy();
}
// 获取音乐总时长
public int getTotalDuration() {
return mediaPlayer.getDuration();
}
// 获取音乐当前播放进度
public int getCurrentPosition() {
return mediaPlayer.getCurrentPosition();
}
// 设置音乐播放进度
public void seekTo(int position) {
mediaPlayer.seekTo(position);
}
}
实现效果
最重要的是能在
后台播放音乐