Android 开发技巧:音乐播放器的后台处理【Service、Handler、MediaPlayer】
最佳答案 问答题库878位专家为你答疑解惑
给定部分完成的MusicPlayer项目,实现其中未完成的service部分:
1、创建MusicService类,通过service组件实现后台播放音乐的功能;
2、在MainActivity中通过ServiceConnection连接MusicService,实现对音乐播放的控制;
3、使用Handler机制在MainActivity和MusicService之间进行通信。
目前已有代码:
相关的资源文件,可自行寻找
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="160dp"tools:ignore="UselessParent"><RelativeLayoutandroid: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"><TextViewandroid: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"/><TextViewandroid: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" /><SeekBarandroid: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" /><RelativeLayoutandroid:layout_marginTop="4dp"android:id="@+id/rl_time"android:layout_width="150dp"android:layout_height="wrap_content"android:layout_below="@id/tv_type"><TextViewandroid: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" /><TextViewandroid: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><LinearLayoutandroid: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"><Buttonandroid: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" /><Buttonandroid: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" /><Buttonandroid: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" /><Buttonandroid: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><ImageViewandroid: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;@Overrideprotected 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() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, booleanfromUser) { //滑动条进度改变时,会调用此方法if (progress == seekBar.getMax()) { //当滑动条滑到末端时,结束动画animator.pause(); //停止播放动画}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {//滑动条开始滑动时调用}@Overridepublic 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表示设置动画无限循环}@Overridepublic 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;}}@Overrideprotected void onDestroy() {super.onDestroy();//解绑服务}
}
当前已经有一个用户界面,其中包括了播放、暂停、继续播放和退出按钮,以及一个旋转动画效果。现在,我们需要将MusicService与MainActivity连接起来,以实现音乐的播放和控制功能。
步骤1:创建MusicService类
单击鼠标右键并选择【New】–>【Service】–>【Service】
步骤 1: 创建 MusicService 类
首先,你需要创建一个名为 MusicService
的类,该类将负责处理音乐播放和与 MainActivity 之间的通信。
这里你需要准备一个mp3格式的文件
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() {}@Overridepublic IBinder onBind(Intent intent) {return new MusicBinder();}public class MusicBinder extends Binder {MusicService getService() {return MusicService.this;}}@Overridepublic 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();}}@Overridepublic 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() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {MusicService.MusicBinder binder = (MusicService.MusicBinder) service;musicService = binder.getService();isBound = true;}@Overridepublic 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,发送消息给MainActivityprivate void updateUI(int progress, int totalDuration) {if (handler != null) {Message message = Message.obtain(handler, UPDATE_UI, progress, totalDuration);handler.sendMessage(message);}}@Overridepublic void onCreate() {super.onCreate();mediaPlayer = MediaPlayer.create(this, R.raw.music); // 加载音乐资源mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {// 音乐播放完成时的处理}});// 定时发送消息以更新UIRunnable runnable = new Runnable() {@Overridepublic 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()) {@Overridepublic 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() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {MusicService.MusicBinder binder = (MusicService.MusicBinder) service;musicService = binder.getService();isBound = true;// 获取音乐总时长并更新UIint totalDuration = musicService.getTotalDuration();updateTotalDuration(totalDuration);}@Overridepublic 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() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {if (progress == seekBar.getMax()) {animator.pause();}updateProgress(progress);}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic 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() {@Overridepublic void onCompletion(MediaPlayer mp) {// 音乐播放完成时的处理animator.pause(); // 停止动画}
});
- 左侧动的文字内容无法到达最大值: 为了确保在音乐播放完成后左侧的时间文本达到最大值,我们在音乐播放完成回调中更新了左侧的时间文本。通过调用
tv_progress.setText(formatDuration(getTotalDuration()))
,我们将左侧的时间文本设置为音乐的总时长,以表明音乐已完成
@Overridepublic void onCreate() {
//……@Overridepublic 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();}@Overridepublic void onCreate() {
//……@Overridepublic 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() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {MusicService.MusicBinder binder = (MusicService.MusicBinder) service;musicService = binder.getService();isBound = true;// 获取音乐总时长并更新UIint totalDuration = musicService.getTotalDuration();updateTotalDuration(totalDuration);}@Overridepublic void onServiceDisconnected(ComponentName name) {isBound = false;}};public final static Handler handler = new Handler(Looper.getMainLooper()) {@Overridepublic 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));}@Overrideprotected 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() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {if (progress == seekBar.getMax()) {animator.pause();}updateProgress(progress);}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic 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表示设置动画无限循环}@Overridepublic 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;}}@Overrideprotected void onStart() {super.onStart();Intent intent = new Intent(this, MusicService.class);bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);}@Overrideprotected 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() {}@Overridepublic 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();}@Overridepublic void onCreate() {super.onCreate();mediaPlayer = MediaPlayer.create(this, R.raw.music); // 加载音乐资源mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {// 音乐播放完成时的处理animator.pause(); // 停止动画tv_progress.setText(formatDuration(getTotalDuration()));showToast("音乐已完成"); // 显示音乐播放完成的提示}});// 定时发送消息以更新UIRunnable runnable = new Runnable() {@Overridepublic 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,发送消息给MainActivityprivate 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();}}@Overridepublic 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);}}
实现效果
最重要的是能在
后台播放音乐
99%的人还看了
相似问题
- KT142C语音芯片音乐前要空白音才行,声音会被截掉,实际语音是你好,播放变成好
- 控制您的音乐、视频等媒体内容
- 【开源】基于Vue.js的音乐偏好度推荐系统的设计和实现
- 基于单片机音乐弹奏播放DS1302万年历显示及源程序
- 《015.SpringBoot+vue之音乐网》【前后端分离】
- C语言 音乐播放器项目(综合)
- asp.net 在线音乐网站系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
- 音乐免费下载mp3格式+音频格式转换+剪辑音频+合并音频教程
- Qt 项目实战 | 音乐播放器
- 案例研究|腾讯音乐娱乐集团与JumpServer共探安全运维审计解决方案
猜你感兴趣
版权申明
本文"Android 开发技巧:音乐播放器的后台处理【Service、Handler、MediaPlayer】":http://eshow365.cn/6-21085-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!
- 上一篇: [计算机提升] 计算机进阶概念:路径
- 下一篇: 【C++】stackqueue