ANDROID_MARS学习笔记_S01原始版_023_MP3PLAYER005_用广播BroacastReciever实现后台播放不更新歌词

时间:2021-11-01 19:21:57

一、代码流程
1.自定义一个AppConstant.LRC_MESSAGE_ACTION字符串表示广播"更新歌词"

2.在PlayerActivity的onResume()注册BroadcastReceiver,在onPause解除BroadcastReceiver

3.自定义LrcMessageBroadcastReceiver继承BroadcastReceiver,在onCreate()通过intent获取歌词,更新UI

4.所有更新歌词的操作移到PlayerService中
二、代码
1.xml

2.java
(1)PlayerActivity.java

 package tony.mp3player;

 import tony.model.Mp3Info;
import tony.mp3player.service.PlayerService;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView; //更新歌词的工作不再在activity中完成,Activity只被动地接收service的广播以更新歌词,
//原来的相关歌词操作挪到service中完成
public class PlayerActivity extends Activity { private ImageButton beginBtn = null;
private ImageButton pauseBtn = null;
private ImageButton stopBtn = null; private TextView lrcTextView = null;
private Mp3Info info = null; private IntentFilter intentFilter = null;
private BroadcastReceiver receiver = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.player);
Intent intent = getIntent();
info = (Mp3Info) intent.getSerializableExtra("mp3Info");
beginBtn = (ImageButton) findViewById(R.id.begin);
pauseBtn = (ImageButton) findViewById(R.id.pause);
stopBtn = (ImageButton) findViewById(R.id.stop);
lrcTextView = (TextView) findViewById(R.id.lrcText); beginBtn.setOnClickListener(new BeginListener());
pauseBtn.setOnClickListener(new PauseListener());
stopBtn.setOnClickListener(new StopListener());
} @Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
} @Override
protected void onResume() {
super.onResume();
receiver = new LrcMessageBroadcastReceiver();
registerReceiver(receiver, getIntentFilter());
} private IntentFilter getIntentFilter() {
if(intentFilter == null) {
intentFilter = new IntentFilter();
intentFilter.addAction(AppConstant.LRC_MESSAGE_ACTION);
}
return intentFilter;
} /**
* 广播接收器,主要接收service放送的广播,并且更新UI,也就是放置歌词 的textview
* @author T
*
*/
class LrcMessageBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String lrcMessage = intent.getStringExtra("lrcMessage");
lrcTextView.setText(lrcMessage);
}
} class BeginListener implements OnClickListener {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("mp3Info", info);
intent.putExtra("MSG", AppConstant.PlayerMsg.PLAY_MSG);
intent.setClass(PlayerActivity2.this, PlayerService.class);
startService(intent);
}
} class PauseListener implements OnClickListener {
@Override
public void onClick(View v) {
//通知Service暂停播放MP3
Intent intent = new Intent();
intent.putExtra("MSG", AppConstant.PlayerMsg.PAUSE_MSG);
intent.setClass(PlayerActivity2.this, PlayerService.class);
startService(intent);
}
} class StopListener implements OnClickListener {
@Override
public void onClick(View v) {
//通知Service停止播放MP3文件
Intent intent = new Intent();
intent.putExtra("MSG", AppConstant.PlayerMsg.STOP_MSG);
intent.setClass(PlayerActivity2.this, PlayerService.class);
startService(intent);
}
}
}

(2)PlayerService.java

 package tony.mp3player.service;

 import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.Queue; import tony.model.Mp3Info;
import tony.mp3player.AppConstant;
import tony.mp3player.LrcProcessor;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder; public class PlayerService extends Service { private boolean isPlaying = false;
private boolean isPause = false;
private boolean isReleased = false;
private MediaPlayer mediaPlayer = null; private Mp3Info info = null;
private List<Queue> queues = null;
private Handler handler = new Handler();
private UpdateTimeCallback updateTimeCallback = null;
private long begin = 0;
private long nextTimeMill = 0;
private long currentTimeMill = 0;
private String msg = null;
private long pauseTimeMills = 0; @Override
public IBinder onBind(Intent intent) {
return null;
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
info = (Mp3Info) intent.getSerializableExtra("mp3Info");
int MSG = intent.getIntExtra("MSG", 0);
if(info != null) {
if(MSG == AppConstant.PlayerMsg.PLAY_MSG) {
play(info);
}
} else {
if(MSG == AppConstant.PlayerMsg.PAUSE_MSG) {
pause();
}
else if(MSG == AppConstant.PlayerMsg.STOP_MSG) {
stop();
}
}
return super.onStartCommand(intent, flags, startId);
} /**
* 根据歌词文件的名字,来读取歌词文件当中的信息
* @param lrcName
*/
private void prepareLrc(String lrcName) {
try {
InputStream inputStream;
inputStream = new FileInputStream(Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + "mp3" + File.separator + info.getLrcName());
LrcProcessor lrcProcessor = new LrcProcessor();
queues = lrcProcessor.process(inputStream);
updateTimeCallback = new UpdateTimeCallback(queues);
begin = 0;
currentTimeMill = 0;
nextTimeMill = 0;
} catch (Exception e) {
e.printStackTrace();
}
} class UpdateTimeCallback implements Runnable{
Queue<Long> times = null;
Queue<String> msgs = null; public UpdateTimeCallback(List<Queue> queues) {
this.times = queues.get(0);
this.msgs = queues.get(1);
} @Override
public void run() {
//计算偏移量,也就是说从开始播放MP3到现在为止,共消耗了多少时间,以毫秒为单位
long offset = System.currentTimeMillis() - begin;
if(currentTimeMill == 0) {//刚开始播放时,调用prepareLrc(),在其中设置currentTimeMill=0
nextTimeMill = times.poll();
msg = msgs.poll();
}
//歌词的显示是如下:例如
//[00:01.00]Look
//[00:03.00]Up
//[00:06.00]Down
//则在第1~3秒间是显示“look”,在第3~6秒间是显示"Up",在第6秒到下一个时间点显示"Down"
if(offset >= nextTimeMill) {
//发送广播,把此刻应该显示的歌词传出去
Intent intent = new Intent();
intent.setAction(AppConstant.LRC_MESSAGE_ACTION);
intent.putExtra("lrcMessage", msg);
sendBroadcast(intent);
msg = msgs.poll();
nextTimeMill = times.poll();
}
currentTimeMill = currentTimeMill + 100;
//在run方法里调用postDelayed,则会形成循环,每0.01秒执行一次线程
handler.postDelayed(updateTimeCallback, 100);
}
} private void play(Mp3Info info) {
if(!isPlaying) {
String path = getMp3Path(info);
mediaPlayer = MediaPlayer.create(this, Uri.parse("file://" + path));
mediaPlayer.setLooping(false);
mediaPlayer.start();
isPlaying = true;
isReleased = false; prepareLrc(info.getLrcName());
handler.postDelayed(updateTimeCallback, 5);
begin = System.currentTimeMillis();
}
} private void pause() {
if(mediaPlayer != null) {
if(!isReleased){
if(!isPause) {
mediaPlayer.pause();
//不再更新歌词
handler.removeCallbacks(updateTimeCallback);
//用来下面代码计算暂停了多久
pauseTimeMills = System.currentTimeMillis();
} else {
mediaPlayer.start();
handler.postDelayed(updateTimeCallback, 5);
//因为下面的时间偏移是这样计算的offset = System.currentTimeMillis() - begin;
//所以要把暂停的时间加到begin里去,
begin = System.currentTimeMillis() - pauseTimeMills + begin;
}
isPause = !isPause;
isPlaying = !isPlaying;
}
}
} private void stop() {
if(mediaPlayer != null) {
if(isPlaying) {
if(!isReleased) {
//从Handler当中移除updateTimeCallback
handler.removeCallbacks(updateTimeCallback);
mediaPlayer.stop();
mediaPlayer.release();
isReleased = true;
isPlaying = false;
}
}
}
} private String getMp3Path(Mp3Info mp3Info) {
String SDCardRoot = Environment.getExternalStorageDirectory()
.getAbsolutePath();
String path = SDCardRoot + File.separator + "mp3" + File.separator
+ mp3Info.getMp3Name();
return path;
}
}