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

一、代码流程
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

  1 package tony.mp3player;
  2 
  3 import tony.model.Mp3Info;
  4 import tony.mp3player.service.PlayerService;
  5 import android.app.Activity;
  6 import android.content.BroadcastReceiver;
  7 import android.content.Context;
  8 import android.content.Intent;
  9 import android.content.IntentFilter;
 10 import android.os.Bundle;
 11 import android.view.View;
 12 import android.view.View.OnClickListener;
 13 import android.widget.ImageButton;
 14 import android.widget.TextView;
 15 
 16 //更新歌词的工作不再在activity中完成,Activity只被动地接收service的广播以更新歌词,
 17 //原来的相关歌词操作挪到service中完成
 18 public class PlayerActivity extends Activity {
 19 
 20     private ImageButton beginBtn = null;
 21     private ImageButton pauseBtn = null;
 22     private ImageButton stopBtn = null;
 23     
 24     private TextView lrcTextView = null;
 25     private Mp3Info info = null;
 26     
 27     private IntentFilter intentFilter = null;
 28     private BroadcastReceiver receiver = null;
 29     
 30     @Override
 31     protected void onCreate(Bundle savedInstanceState) {
 32         super.onCreate(savedInstanceState);
 33         setContentView(R.layout.player);
 34         Intent intent = getIntent();
 35         info = (Mp3Info) intent.getSerializableExtra("mp3Info");
 36         beginBtn = (ImageButton) findViewById(R.id.begin);
 37         pauseBtn = (ImageButton) findViewById(R.id.pause);
 38         stopBtn = (ImageButton) findViewById(R.id.stop);
 39         lrcTextView = (TextView) findViewById(R.id.lrcText);
 40         
 41         beginBtn.setOnClickListener(new BeginListener());
 42         pauseBtn.setOnClickListener(new PauseListener());
 43         stopBtn.setOnClickListener(new StopListener());
 44     }
 45     
 46     @Override
 47     protected void onPause() {
 48         super.onPause();
 49         unregisterReceiver(receiver);
 50     }
 51     
 52     @Override
 53     protected void onResume() {
 54         super.onResume();
 55         receiver = new LrcMessageBroadcastReceiver();
 56         registerReceiver(receiver, getIntentFilter());
 57     }
 58     
 59     private IntentFilter getIntentFilter() {
 60         if(intentFilter == null) {
 61             intentFilter = new IntentFilter();
 62             intentFilter.addAction(AppConstant.LRC_MESSAGE_ACTION);
 63         }
 64         return intentFilter;
 65     }
 66 
 67     /**
 68      * 广播接收器,主要接收service放送的广播,并且更新UI,也就是放置歌词 的textview
 69      * @author T
 70      *
 71      */
 72     class LrcMessageBroadcastReceiver extends BroadcastReceiver {
 73         public void onReceive(Context context, Intent intent) {
 74             String lrcMessage = intent.getStringExtra("lrcMessage");
 75             lrcTextView.setText(lrcMessage);
 76         }
 77     }
 78     
 79     
 80     class BeginListener implements OnClickListener {
 81         @Override
 82         public void onClick(View v) {
 83             Intent intent = new Intent();
 84             intent.putExtra("mp3Info", info);
 85             intent.putExtra("MSG", AppConstant.PlayerMsg.PLAY_MSG);
 86             intent.setClass(PlayerActivity2.this, PlayerService.class);
 87             startService(intent);
 88         }
 89     }
 90     
 91     class PauseListener implements OnClickListener {
 92         @Override
 93         public void onClick(View v) {
 94             //通知Service暂停播放MP3
 95             Intent intent = new Intent();
 96             intent.putExtra("MSG", AppConstant.PlayerMsg.PAUSE_MSG);
 97             intent.setClass(PlayerActivity2.this, PlayerService.class);
 98             startService(intent);
 99         }
100     }
101     
102     class StopListener implements OnClickListener {
103         @Override
104         public void onClick(View v) {
105             //通知Service停止播放MP3文件
106             Intent intent = new Intent();
107             intent.putExtra("MSG", AppConstant.PlayerMsg.STOP_MSG);
108             intent.setClass(PlayerActivity2.this, PlayerService.class);
109             startService(intent);
110         }
111     }
112 }

(2)PlayerService.java

  1 package tony.mp3player.service;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.InputStream;
  6 import java.util.List;
  7 import java.util.Queue;
  8 
  9 import tony.model.Mp3Info;
 10 import tony.mp3player.AppConstant;
 11 import tony.mp3player.LrcProcessor;
 12 import android.app.Service;
 13 import android.content.Intent;
 14 import android.media.MediaPlayer;
 15 import android.net.Uri;
 16 import android.os.Environment;
 17 import android.os.Handler;
 18 import android.os.IBinder;
 19 
 20 
 21 
 22 public class PlayerService extends Service {
 23 
 24     private boolean isPlaying = false;
 25     private boolean isPause = false;
 26     private boolean isReleased = false;
 27     private MediaPlayer mediaPlayer = null;
 28     
 29     private Mp3Info info = null;
 30     private List<Queue> queues = null;
 31     private Handler handler = new Handler();
 32     private UpdateTimeCallback updateTimeCallback = null;
 33     private long begin = 0;
 34     private long nextTimeMill = 0;
 35     private long currentTimeMill = 0;
 36     private String msg = null;
 37     private long pauseTimeMills = 0;
 38     
 39     @Override
 40     public IBinder onBind(Intent intent) {
 41         return null;
 42     }
 43 
 44     @Override
 45     public int onStartCommand(Intent intent, int flags, int startId) {
 46         info = (Mp3Info) intent.getSerializableExtra("mp3Info");
 47         int MSG = intent.getIntExtra("MSG", 0);
 48         if(info != null) {
 49             if(MSG == AppConstant.PlayerMsg.PLAY_MSG) {
 50                 play(info);
 51             }
 52         } else {
 53             if(MSG == AppConstant.PlayerMsg.PAUSE_MSG) {
 54                 pause();
 55             } 
 56             else if(MSG == AppConstant.PlayerMsg.STOP_MSG) {
 57                 stop();
 58             }
 59         }
 60         return super.onStartCommand(intent, flags, startId);
 61     }
 62     
 63     /**
 64      * 根据歌词文件的名字,来读取歌词文件当中的信息
 65      * @param lrcName
 66      */
 67     private void prepareLrc(String lrcName) {
 68         try {
 69             InputStream inputStream;
 70             inputStream = new FileInputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + 
 71                     File.separator + "mp3" + File.separator + info.getLrcName());
 72             LrcProcessor lrcProcessor = new LrcProcessor();
 73             queues = lrcProcessor.process(inputStream);
 74             updateTimeCallback = new UpdateTimeCallback(queues);
 75             begin = 0;
 76             currentTimeMill = 0;
 77             nextTimeMill = 0;
 78         } catch (Exception e) {
 79             e.printStackTrace();
 80         }
 81     }
 82     
 83     class UpdateTimeCallback implements Runnable{
 84         Queue<Long> times = null;
 85         Queue<String> msgs = null;
 86         
 87         public UpdateTimeCallback(List<Queue> queues) {
 88             this.times = queues.get(0);
 89             this.msgs = queues.get(1);
 90         }
 91     
 92         @Override
 93         public void run() {
 94             //计算偏移量,也就是说从开始播放MP3到现在为止,共消耗了多少时间,以毫秒为单位
 95             long offset = System.currentTimeMillis() - begin;
 96             if(currentTimeMill == 0) {//刚开始播放时,调用prepareLrc(),在其中设置currentTimeMill=0
 97                 nextTimeMill = times.poll();
 98                 msg = msgs.poll();
 99             }
100             //歌词的显示是如下:例如
101             //[00:01.00]Look
102             //[00:03.00]Up
103             //[00:06.00]Down
104             //则在第1~3秒间是显示“look”,在第3~6秒间是显示"Up",在第6秒到下一个时间点显示"Down"
105             if(offset >= nextTimeMill) {
106                 //发送广播,把此刻应该显示的歌词传出去
107                 Intent intent = new Intent();
108                 intent.setAction(AppConstant.LRC_MESSAGE_ACTION);
109                 intent.putExtra("lrcMessage", msg);
110                 sendBroadcast(intent);
111                 msg = msgs.poll();
112                 nextTimeMill = times.poll();
113             }
114             currentTimeMill = currentTimeMill + 100;
115             //在run方法里调用postDelayed,则会形成循环,每0.01秒执行一次线程
116             handler.postDelayed(updateTimeCallback, 100);
117         }
118     }
119     
120     private void play(Mp3Info info) {
121         if(!isPlaying) {
122             String path = getMp3Path(info);
123             mediaPlayer = MediaPlayer.create(this, Uri.parse("file://" + path));
124             mediaPlayer.setLooping(false);
125             mediaPlayer.start();
126             isPlaying = true;
127             isReleased = false;
128             
129             prepareLrc(info.getLrcName());
130             handler.postDelayed(updateTimeCallback, 5);
131             begin = System.currentTimeMillis();
132         }
133     }
134     
135     private void pause() {
136         if(mediaPlayer != null) {
137             if(!isReleased){
138                 if(!isPause) {
139                     mediaPlayer.pause();
140                     //不再更新歌词
141                     handler.removeCallbacks(updateTimeCallback);
142                     //用来下面代码计算暂停了多久
143                     pauseTimeMills = System.currentTimeMillis();
144                 } else {
145                     mediaPlayer.start();
146                     handler.postDelayed(updateTimeCallback, 5);
147                     //因为下面的时间偏移是这样计算的offset = System.currentTimeMillis() - begin;
148                     //所以要把暂停的时间加到begin里去,
149                     begin = System.currentTimeMillis() - pauseTimeMills + begin;
150                 }
151                 isPause = !isPause;
152                 isPlaying = !isPlaying;
153             }
154         }
155     }
156     
157     private void stop() {
158         if(mediaPlayer != null) {
159             if(isPlaying) {
160                 if(!isReleased) {
161                     //从Handler当中移除updateTimeCallback
162                     handler.removeCallbacks(updateTimeCallback);
163                     mediaPlayer.stop();
164                     mediaPlayer.release();
165                     isReleased = true;
166                     isPlaying = false;
167                 }
168             }
169         }
170     }
171 
172     private String getMp3Path(Mp3Info mp3Info) {
173         String SDCardRoot = Environment.getExternalStorageDirectory()
174                 .getAbsolutePath();
175         String path = SDCardRoot + File.separator + "mp3" + File.separator
176                 + mp3Info.getMp3Name();
177         return path;
178     }
179 }
原文地址:https://www.cnblogs.com/shamgod/p/5198902.html