• 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 }
  • 相关阅读:
    HDFS Namenode 高可用
    旁路模式,numa、mmu、调整内存分页大小
    k8s 调度 GPU
    破解 CSDN 登录后才能复制
    微信小程序开发video遮罩功能(禁止拖动进度条)
    微信小程序之下拉刷新
    微信小程序JS中文排序
    vue2 和 vue3 路由使用对比
    Golang 操作mongo
    win10安装CUDA和cuDNN的正确姿势
  • 原文地址:https://www.cnblogs.com/shamgod/p/5198902.html
Copyright © 2020-2023  润新知