Given the partially completed MusicPlayer project, implement the unfinished service part:
1. Create the MusicService class and implement the function of playing music in the background through the service component;
2. Connect to MusicService through ServiceConnection in MainActivity to control music playback;
3. Use Handler mechanism to communicate between MainActivity and MusicService.
There is currently code:
Relevant resource files can be found by yourself
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">
<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();
//解绑服务
}
}
There is already a user interface that includes play, pause, resume, and exit buttons, as well as a rotation animation effect. Now, we need to connect MusicService with MainActivity to implement music playback and control functions.
Step 1: Create MusicService class
Right-click the mouse and select [New]–>[Service]–>[Service]
Step 1: Create MusicService class
First, you need to create a class named MusicService
which will be responsible for handling music playback and communication with MainActivity.
Here you need to prepare a file in mp3 format
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();
}
}
Related variable description:
-
MusicService
It is an Android service class used to handle functions related to music playback. -
mediaPlayer
It is a MediaPlayer object used to play music. It is responsible for loading music resources, playing, pausing and continuing to play music. -
MusicBinder
The inner class inherits from Binder and is used for communication between the binding service and other components. -
onBind
The method is used to return aMusicBinder
object so that other components can bind to the service. -
onCreate
The method is called when the service is created, which initializesmediaPlayer
and loads the music resources. In this example, the music resource is loaded fromR.raw.music
. -
playMusic
The method is used to play music. If the music is not playing, callmediaPlayer.start()
to start playing. -
pauseMusic
The method is used to pause the music. If the music is playing, callmediaPlayer.pause()
to pause it. -
continueMusic
The method is used to continue playing music. If the music has been paused, callmediaPlayer.start()
to continue playing. -
onDestroy
The method is called when the service is destroyed, and it releases the resources of themediaPlayer
object to ensure that no memory leaks occur.
The service allows other components to bind to it to control the playing, pausing and resuming of music; loads a music resource (in this case R.raw.music
) and uses MediaPlayer
object plays music
Register MusicService in AndroidManifest.xml (check)
Make sure to register MusicService in AndroidManifest.xml file so that the application can start the service normally.
Generally, after we create the service file, it will be automatically registered
<service android:name=".MusicService" />
Step 2: Connect MusicService in MainActivity
In MainActivity
, add code to connect to MusicService
and control the music to play, pause, and resume.
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;
}
}
Step 3: Call the MusicService method in MainActivity
Call the method of in the onClick
method to control the playback, pause and continuation of music. 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;
}
}
Currently, we have initially completed the play, pause, continue, and exit functions of the simple music player;
You can try running the project at this time to test the effect!
Step 4: Modify MusicService (to implement communication update UI)
Add function to obtain relevant information
// 获取音乐总时长
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);
}
This code adds some important functionality to MusicService
to communicate with MainActivity
and update the UI. Here is a description of the code:
-
getTotalDuration
The function is used to get the total duration of the music. It gets the total duration of the music through themediaPlayer.getDuration()
method and returns that value. -
getCurrentPosition
function is used to get the current playback progress of music. Get the current playback progress of the music through themediaPlayer.getCurrentPosition()
method, and then return this value. -
seekTo
The function is used to set the music playback progress. Accepts an integer parameterposition
, indicating the music playback progress to be set, and uses themediaPlayer.seekTo(position)
method to jump the progress. -
updateUI
The function is used to send a message toMainActivity
in order to update the UI element. It accepts two parameters, namely the current playback progressprogress
and the total duration of the musictotalDuration
. It creates aMessage
object and sends messages to viahandler.sendMessage(message)
in order to update UI elements such as progress bars and text.MainActivity
-
In the
onCreate
method, send messages regularly to update the UI. Through aRunnable
scheduled task, obtain the current playback progress and total music duration, and then call theupdateUI
function to send a message toMainActivity
. To achieve the purpose of constantly updating UI elements.
These functions and logic enable MusicService
to communicate with MainActivity
, passing the music playback progress and total duration so that MainActivity
Ability to update UI elements to provide a user-friendly music playback experience.
Step 5: Modify MainActivity (to achieve communication update UI)
Get the total duration of music in MusicService, and update the position of tv_total and the progress bar in MainActivity, as well as the total duration and progress of formatted music.
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 方法用于定位音乐进度
}
});
// ...
This code adds communication between MainActivity
and MusicService
in order to dynamically update the progress of music playback and display the total duration of music. . Here is a description of the code:
-
defines a in
MainActivity
, which is a static object that is used to handle the Message sent to update UI elements. The message type is identified by the constant.handler
Handler
MusicService
UPDATE_UI
-
updateUI
The function is the core method for updating UI elements. Accepts two parameters, namely the current playback progressprogress
and the total duration of the musictotalDuration
. In this method, the position of the progress bar will be set to the current playback progress, the text on the lefttv_progress
will be updated to the formatted playback progress, and the total duration text on the left will be updated to the formatted playback progress. a>tv_total
will be updated to the total duration of the formatted music. -
updateProgress
The method is a helper method used to update the playback progress. Accepts a parameterprogress
, and updates the text on the lefttv_progress
to the formatted playback progress. -
formatDuration
The method is a helper method used to format music duration. Accepts an integerduration
representing the duration of the music in milliseconds, and formats it as minutes:seconds. -
updateTotalDuration
The method is used to update the total duration. It accepts a parameterduration
, indicating the total duration of the music, and updates the total duration text on the lefttv_total
to the formatted total duration of the music, and sets the progress bar The maximum value is the total duration of the music. -
In
serviceConnection
, whenMusicService
andMainActivity
are successfully connected, the total duration of the music will be obtained and < /span>updateTotalDuration
method to update UI elements. -
In the event listener of
sb
(SeekBar), through theonProgressChanged
method, when the progress of the progress bar changes, it will be called method is called to locate the progress of the music. method, when the user drags the progress bar, theupdateProgress
method to update the playback progress text on the left. In theonStopTrackingTouch
musicService.seekTo(progress)
These code changes enable MainActivity
to work together with MusicService
to achieve dynamic updates of music playback progress and display of the total music duration. This is essential to provide a user-friendly music playback experience.
Step 6: Add processing details after the music ends
For these new problems, we can make the following modifications and processing:
- Stop animation: The animation should stop as the music completes. We added a music playback completion callback in
MusicService
to pause the animation when the music ends. This way, the user can see that the music is complete while the animation is no longer rotating, providing a clear visual indication. As shown below:
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// 音乐播放完成时的处理
animator.pause(); // 停止动画
}
});
- The moving text content on the left cannot reach the maximum value: In order to ensure that the time text on the left reaches the maximum value after the music playback is completed, we updated it in the music playback completion callback Time text on the left. By calling
tv_progress.setText(formatDuration(getTotalDuration()))
we set the time text on the left to the total duration of the music to indicate that the music is complete
@Override
public void onCreate() {
//……
@Override
public void onCompletion(MediaPlayer mp) {
// 音乐播放完成时的处理
animator.pause(); // 停止动画
tv_progress.setText(formatDuration(getTotalDuration()));
}
});
}
- No reminder when music is complete: We added a way to notify the user that music is complete. In the music playback completion callback in
MusicService
, we use theshowToast
function to display a short prompt message. This reminder can be expanded based on your needs, for example, you can choose to display a notification, perform additional actions, or add more user feedback.
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("音乐已完成"); // 显示音乐播放完成的提示
}
});
}
Complete code
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);
}
}
achieve effect
The most important thing is to be able to
后台播放音乐