Chinaunix首页 | 论坛 | 博客
  • 博客访问: 200330
  • 博文数量: 102
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1015
  • 用 户 组: 普通用户
  • 注册时间: 2013-06-05 16:45
文章存档

2014年(73)

2013年(29)

我的朋友

分类: Android平台

2014-04-06 16:40:09

Mp3Player(5) PlayerService、Service、BroadcastReciver、Handler、Runnable

点击(此处)折叠或打开

  1. //PlayerService.java
  2. package com.lwb.mp3player.service;

  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileNotFoundException;
  6. import java.io.InputStream;
  7. import java.util.ArrayList;
  8. import java.util.Queue;

  9. import com.lwb.lrc.LrcProcessor;
  10. import com.lwb.model.Mp3Info;
  11. import com.lwb.mp3player.AppConstant;
  12. import com.lwb.mp3player.PlayerActivity;

  13. import android.app.Service;
  14. import android.content.Intent;
  15. import android.media.MediaPlayer;
  16. import android.net.Uri;
  17. import android.os.Environment;
  18. import android.os.Handler;
  19. import android.os.IBinder;

  20. public class PlayerService extends Service {
  21.     
  22.     MediaPlayer mediaPlayer = null;
  23.     private boolean isPlaying = false;
  24.     private boolean isPause = false;
  25.     private boolean isReleased = false;
  26.     private Mp3Info mp3Info;

  27.     private UpdatetimeCallback updateTimeCallback = null;
  28.     private long nextTimeMill = 0;
  29.     private long begin = 0;
  30.     private long currentTimeMill = 0;
  31.     private String message = null;
  32.     private long pauseTimeMills = 0;
  33.     private ArrayList<Queue> queues = null;    
  34.     private Handler handler = new Handler();// 创建一个Handler()对象
  35.     /*Handle主要接受子线程发送的数据, 并用此数据配合主线程更新UI.
  36.      * ,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),
  37.      * 它与子线程可以通过Message对象来传递数据,这个时候,
  38.      * Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象(里面包含数据),
  39.      * 把这些消息放入主线程队列中,配合主线程进行更新UI。
  40.      */
  41.     
  42.     @Override
  43.     public IBinder onBind(Intent arg0) {
  44.         return null;
  45.     }

  46.     /*onStartCommand(Intent intent, int flags, int startId)
  47.      * 每次Activity向Service发送Intent的时候都会执行onStartCommand()
  48.      *从intent中得到Activity中发送来的信息
  49.      *MP3Info(Mp3Info)intent.getSerializableExtra("mp3Info");
  50.      *msg = intent.getIntExtra("MSG",0);
  51.      *并更加信息对歌曲播放的歌曲进行设置*/
  52.     @Override
  53.     public int onStartCommand(Intent intent, int flags, int startId) {
  54.         mp3Info = (Mp3Info) intent.getSerializableExtra("mp3Info");// 得到mp3的名字
  55.         int MSG = intent.getIntExtra("MSG", 0); // 得到一个MSG
  56.         if (mp3Info != null) {
  57.             if (MSG == AppConstant.PlayerMsg.PLAY_MSG) {
  58.                 play(mp3Info);
  59.             } else {
  60.                 if (MSG == AppConstant.PlayerMsg.PAUSE_MSG) {
  61.                     pause();
  62.                 } else if (MSG == AppConstant.PlayerMsg.STOP_MSG) {
  63.                     stop();
  64.                 }
  65.             }
  66.         }
  67.         return super.onStartCommand(intent, flags, startId);
  68.     }

  69.     /*play(Mp3Info mp3Info)播放mp3info中的歌曲
  70.      * 1、获得歌曲的名字fileName = mp3Info.getMp3Name().substring(0,mp3Info,getMp3Name(),lastIndexof(.));
  71.      * fileName=fileName+".lrc";
  72.      * 2、预处理歌词prepareLrc("mp3/"+fileName);
  73.      * 3、获得歌曲所在存储器中的路径path = getMp3Path(mp3Info)这个方法是自己实现的
  74.      * 4、创建一个MediaPlayer:mediaPlayer = MediaPlayer.create(PlayerService.this,Uri.parse("file://"+path))
  75.      * 其中PlayerService.this表这个MediaPlayer是在这个Service上的,歌曲在Uri.parse("file://"+path)上
  76.      * 5、设置为不循环播放mediaPlayer.setLooping(false)
  77.      * 6、开始播放歌曲:mediaPlayer.start()
  78.      * 7、记录当前播放的时间begin = System.currentTimeMillis()
  79.      * 8、1毫秒之后加入回调线程updateTimeCallcack:handler.postDelayed(updateTimeCallcack,1)进入计算更新歌词*/
  80.     private void play(Mp3Info mp3Info) {
  81.         String fileName=mp3Info.getMp3Name().substring(0,mp3Info.getMp3Name().lastIndexOf("."));
  82.         fileName=fileName+".lrc";
  83.         prepareLrc("mp3/"+fileName);
  84.         String path = getMp3Path(mp3Info);
  85.         mediaPlayer = MediaPlayer.create(PlayerService.this,
  86.                 Uri.parse("file://" + path));
  87.         mediaPlayer.setLooping(false);
  88.         mediaPlayer.start();
  89.         isPlaying = true;
  90.         isReleased = false;
  91.         isPause = false;
  92.         // 将begin表当前毫秒数
  93.         begin = System.currentTimeMillis();
  94.         // 执行updateTimeCallback
  95.         //    handler.postDelayed(updateTimeCallback, 5);
  96.         handler.postDelayed(updateTimeCallback, 1);
  97.     }

  98.     private void pause() {
  99.         if (mediaPlayer != null) {
  100.             if (!isReleased) {
  101.                 if ((!isPause) && isPlaying) {
  102.                     mediaPlayer.pause();
  103.                     isPause = true;
  104.                     isPlaying = false;
  105.                     //移除回调函数
  106.                     handler.removeCallbacks(updateTimeCallback);
  107.                     //获得暂停时刻
  108.                     pauseTimeMills = System.currentTimeMillis();                    
  109.                 } else {
  110.                     //"推出播放开始播放时间"
  111.                     begin = System.currentTimeMillis()- pauseTimeMills + begin;
  112.                     mediaPlayer.start();
  113.                     isPause = false;
  114.                     isPlaying = true;
  115.                     handler.post(updateTimeCallback);                    
  116.                 }
  117.             }
  118.         }
  119.     }

  120.     private void stop() {
  121.         if (mediaPlayer != null) {
  122.             if (isPlaying) {
  123.                 if (!isReleased) {
  124.                     mediaPlayer.stop();
  125.                     mediaPlayer.release();
  126.                     isReleased = true;
  127.                     handler.removeCallbacks(updateTimeCallback);
  128.                 }
  129.                 isPlaying = false;
  130.                 isPause = false;
  131.             }
  132.         }
  133.     }

  134.     /*getMp3Path(Mp3Info mp3Info)获得歌曲所在存储器中的路径
  135.      * 1、获得外部存储器的绝对路径 Environment.getExternalStorageDirectory()
  136.      * 2、生成路径path = SDCardRoot + File.separator +"mp3/" + mp3Info.getMp3Name */
  137.     private String getMp3Path(Mp3Info mp3Info) {
  138.         String SDCardRoot = Environment.getExternalStorageDirectory()
  139.                 .getAbsolutePath();
  140.         String path = SDCardRoot + File.separator + "mp3/"
  141.                 + mp3Info.getMp3Name();
  142.         return path;
  143.     }


  144.     
  145.     /* prepareLrc(String lrcName) 根据歌词文件的名字,读取歌词文件当中的信息
  146.      * 1、创建一个输入流inputStream = new FileInputStream(路径+文件名);
  147.      * 2、创建一个Lrcprocessor自定义对象:lrcProcessor = new LrcProcessor();
  148.      * 3、对歌词文件对象的输入流inputSteam进行处理queues = lrcProcessor.process(inputStream);
  149.      * 得到是一个队列queues,里边包含两个队列,一个是时间,另一个是歌词队列。
  150.      * 4、创建一个UpdatetimeCallback(queues)对象,传入了参数queues,
  151.      * 里边的线程就能根据queues里边的信息计算并发送更新歌词的信息
  152.      */
  153.     private void prepareLrc(String lrcName) {
  154.         try {
  155.             InputStream inputStream = new FileInputStream(Environment
  156.                     .getExternalStorageDirectory().getAbsoluteFile()
  157.                     + "/"
  158.                     + lrcName);// ??????
  159.             LrcProcessor lrcProcessor = new LrcProcessor();
  160.             queues = lrcProcessor.process(inputStream);
  161.             // 创建一个UpdateTimeCallback对象 线程对象
  162.             updateTimeCallback = new UpdatetimeCallback(queues);
  163.             begin = 0;
  164.             currentTimeMill = 0;
  165.             nextTimeMill = 0;
  166.         } catch (FileNotFoundException e) {
  167.             e.printStackTrace();
  168.         }
  169.     }

  170.     /*UpdatetimeCallback实现了Runnable接口并复写了run()函数
  171.      * 1、创建UpdatetimeCallback时,通过构造函数得到队列times和messages
  172.      * 2、run()方法中计算发送显示歌词消息
  173.      * 刚进入
  174.      * 再次进入、、多进入 当 过去的时间偏移量offset>nextTimeMill表要更新歌词
  175.      *     创建一个Intent对象
  176.      *     设置要发送的广播动作intent.setAction(AppConstant.LRC_MESSAGE_ACTION)
  177.      *     设置要放给Activity的歌词intent.putExtra("lrcMessage",message)
  178.      *     发送广播信息sendBroadcast(intent)
  179.      *     播放歌词的时间加10毫秒。currentTimeMill = currentTimeMill + 10;
  180.      * 10毫秒后再次调用回调函数updateTimeCallback:handler.postDelayed(updateTimeCallback, 10);
  181.      *
  182.      * */

  183.     class UpdatetimeCallback implements Runnable {
  184.         Queue times = null;
  185.         Queue messages = null;
  186.         public UpdatetimeCallback(ArrayList<Queue> queues) {
  187.             // 从ArrayList当中取出相应的对象
  188.             times = queues.get(0);
  189.             messages = queues.get(1);
  190.             /*这里整死哥 了,定义成局域变量
  191.              * Queue times = queues.get(0);
  192.              * Queue messages =queues.get(1);
  193.              */
  194.         }

  195.         @Override
  196.         public void run() {
  197.             // 计算偏移量,也就是说从开始播放Mp3到现在为止,共消耗了多少时间,以毫秒为单位
  198.             long offset = System.currentTimeMillis() - begin;
  199.             if (times.size() > 0 && messages.size() > 0) {
  200.                 if (currentTimeMill == 0) {
  201.                     nextTimeMill = (Long) times.poll();// poll()来获取并移出元素
  202.                     message = (String) messages.poll();
  203.                 }
  204.                 if (offset >= nextTimeMill) {
  205.                     Intent intent = new Intent();
  206.                     intent.setAction(AppConstant.LRC_MESSAGE_ACTION);
  207.                     intent.putExtra("lrcMessage", message);
  208.                     sendBroadcast(intent);
  209.                     message = (String) messages.poll();
  210.                     nextTimeMill = (Long) times.poll();
  211.                 }
  212.                 currentTimeMill = currentTimeMill + 10;//从播放歌词到现在经过的时间。 这个变量其实没什么用
  213.                 handler.postDelayed(updateTimeCallback, 10);
  214.             }            
  215.         }
  216.     }
  217.     
  218.     /* mHandler=new Handler();
  219.   mHandler.post(new Runnable(){
  220.   void run(){
  221.   //执行代码...
  222.   }
  223.   });
  224.   这个线程其实是在UI线程之内运行的,并没有新建线程。
  225.   常见的新建线程的方法是:
  226.   Thread thread = new Thread();
  227.   thread.start();
  228.   HandlerThread thread = new HandlerThread("string");
  229.   thread.start();
  230.          详细出处参考:*/
  231. }


阅读(832) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~