Mp3Player(5) PlayerService、Service、BroadcastReciver、Handler、Runnable
-
//PlayerService.java
-
package com.lwb.mp3player.service;
-
-
import java.io.File;
-
import java.io.FileInputStream;
-
import java.io.FileNotFoundException;
-
import java.io.InputStream;
-
import java.util.ArrayList;
-
import java.util.Queue;
-
-
import com.lwb.lrc.LrcProcessor;
-
import com.lwb.model.Mp3Info;
-
import com.lwb.mp3player.AppConstant;
-
import com.lwb.mp3player.PlayerActivity;
-
-
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 {
-
-
MediaPlayer mediaPlayer = null;
-
private boolean isPlaying = false;
-
private boolean isPause = false;
-
private boolean isReleased = false;
-
private Mp3Info mp3Info;
-
-
private UpdatetimeCallback updateTimeCallback = null;
-
private long nextTimeMill = 0;
-
private long begin = 0;
-
private long currentTimeMill = 0;
-
private String message = null;
-
private long pauseTimeMills = 0;
-
private ArrayList<Queue> queues = null;
-
private Handler handler = new Handler();// 创建一个Handler()对象
-
/*Handle主要接受子线程发送的数据, 并用此数据配合主线程更新UI.
-
* ,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),
-
* 它与子线程可以通过Message对象来传递数据,这个时候,
-
* Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象(里面包含数据),
-
* 把这些消息放入主线程队列中,配合主线程进行更新UI。
-
*/
-
-
@Override
-
public IBinder onBind(Intent arg0) {
-
return null;
-
}
-
-
/*onStartCommand(Intent intent, int flags, int startId)
-
* 每次Activity向Service发送Intent的时候都会执行onStartCommand()
-
*从intent中得到Activity中发送来的信息
-
*MP3Info(Mp3Info)intent.getSerializableExtra("mp3Info");
-
*msg = intent.getIntExtra("MSG",0);
-
*并更加信息对歌曲播放的歌曲进行设置*/
-
@Override
-
public int onStartCommand(Intent intent, int flags, int startId) {
-
mp3Info = (Mp3Info) intent.getSerializableExtra("mp3Info");// 得到mp3的名字
-
int MSG = intent.getIntExtra("MSG", 0); // 得到一个MSG
-
if (mp3Info != null) {
-
if (MSG == AppConstant.PlayerMsg.PLAY_MSG) {
-
play(mp3Info);
-
} else {
-
if (MSG == AppConstant.PlayerMsg.PAUSE_MSG) {
-
pause();
-
} else if (MSG == AppConstant.PlayerMsg.STOP_MSG) {
-
stop();
-
}
-
}
-
}
-
return super.onStartCommand(intent, flags, startId);
-
}
-
-
/*play(Mp3Info mp3Info)播放mp3info中的歌曲
-
* 1、获得歌曲的名字fileName = mp3Info.getMp3Name().substring(0,mp3Info,getMp3Name(),lastIndexof(.));
-
* fileName=fileName+".lrc";
-
* 2、预处理歌词prepareLrc("mp3/"+fileName);
-
* 3、获得歌曲所在存储器中的路径path = getMp3Path(mp3Info)这个方法是自己实现的
-
* 4、创建一个MediaPlayer:mediaPlayer = MediaPlayer.create(PlayerService.this,Uri.parse("file://"+path))
-
* 其中PlayerService.this表这个MediaPlayer是在这个Service上的,歌曲在Uri.parse("file://"+path)上
-
* 5、设置为不循环播放mediaPlayer.setLooping(false)
-
* 6、开始播放歌曲:mediaPlayer.start()
-
* 7、记录当前播放的时间begin = System.currentTimeMillis()
-
* 8、1毫秒之后加入回调线程updateTimeCallcack:handler.postDelayed(updateTimeCallcack,1)进入计算更新歌词*/
-
private void play(Mp3Info mp3Info) {
-
String fileName=mp3Info.getMp3Name().substring(0,mp3Info.getMp3Name().lastIndexOf("."));
-
fileName=fileName+".lrc";
-
prepareLrc("mp3/"+fileName);
-
String path = getMp3Path(mp3Info);
-
mediaPlayer = MediaPlayer.create(PlayerService.this,
-
Uri.parse("file://" + path));
-
mediaPlayer.setLooping(false);
-
mediaPlayer.start();
-
isPlaying = true;
-
isReleased = false;
-
isPause = false;
-
// 将begin表当前毫秒数
-
begin = System.currentTimeMillis();
-
// 执行updateTimeCallback
-
// handler.postDelayed(updateTimeCallback, 5);
-
handler.postDelayed(updateTimeCallback, 1);
-
}
-
-
private void pause() {
-
if (mediaPlayer != null) {
-
if (!isReleased) {
-
if ((!isPause) && isPlaying) {
-
mediaPlayer.pause();
-
isPause = true;
-
isPlaying = false;
-
//移除回调函数
-
handler.removeCallbacks(updateTimeCallback);
-
//获得暂停时刻
-
pauseTimeMills = System.currentTimeMillis();
-
} else {
-
//"推出播放开始播放时间"
-
begin = System.currentTimeMillis()- pauseTimeMills + begin;
-
mediaPlayer.start();
-
isPause = false;
-
isPlaying = true;
-
handler.post(updateTimeCallback);
-
}
-
}
-
}
-
}
-
-
private void stop() {
-
if (mediaPlayer != null) {
-
if (isPlaying) {
-
if (!isReleased) {
-
mediaPlayer.stop();
-
mediaPlayer.release();
-
isReleased = true;
-
handler.removeCallbacks(updateTimeCallback);
-
}
-
isPlaying = false;
-
isPause = false;
-
}
-
}
-
}
-
-
/*getMp3Path(Mp3Info mp3Info)获得歌曲所在存储器中的路径
-
* 1、获得外部存储器的绝对路径 Environment.getExternalStorageDirectory()
-
* 2、生成路径path = SDCardRoot + File.separator +"mp3/" + mp3Info.getMp3Name */
-
private String getMp3Path(Mp3Info mp3Info) {
-
String SDCardRoot = Environment.getExternalStorageDirectory()
-
.getAbsolutePath();
-
String path = SDCardRoot + File.separator + "mp3/"
-
+ mp3Info.getMp3Name();
-
return path;
-
}
-
-
-
-
/* prepareLrc(String lrcName) 根据歌词文件的名字,读取歌词文件当中的信息
-
* 1、创建一个输入流inputStream = new FileInputStream(路径+文件名);
-
* 2、创建一个Lrcprocessor自定义对象:lrcProcessor = new LrcProcessor();
-
* 3、对歌词文件对象的输入流inputSteam进行处理queues = lrcProcessor.process(inputStream);
-
* 得到是一个队列queues,里边包含两个队列,一个是时间,另一个是歌词队列。
-
* 4、创建一个UpdatetimeCallback(queues)对象,传入了参数queues,
-
* 里边的线程就能根据queues里边的信息计算并发送更新歌词的信息
-
*/
-
private void prepareLrc(String lrcName) {
-
try {
-
InputStream inputStream = new FileInputStream(Environment
-
.getExternalStorageDirectory().getAbsoluteFile()
-
+ "/"
-
+ lrcName);// ??????
-
LrcProcessor lrcProcessor = new LrcProcessor();
-
queues = lrcProcessor.process(inputStream);
-
// 创建一个UpdateTimeCallback对象 线程对象
-
updateTimeCallback = new UpdatetimeCallback(queues);
-
begin = 0;
-
currentTimeMill = 0;
-
nextTimeMill = 0;
-
} catch (FileNotFoundException e) {
-
e.printStackTrace();
-
}
-
}
-
-
/*UpdatetimeCallback实现了Runnable接口并复写了run()函数
-
* 1、创建UpdatetimeCallback时,通过构造函数得到队列times和messages
-
* 2、run()方法中计算发送显示歌词消息
-
* 刚进入
-
* 再次进入、、多进入 当 过去的时间偏移量offset>nextTimeMill表要更新歌词
-
* 创建一个Intent对象
-
* 设置要发送的广播动作intent.setAction(AppConstant.LRC_MESSAGE_ACTION)
-
* 设置要放给Activity的歌词intent.putExtra("lrcMessage",message)
-
* 发送广播信息sendBroadcast(intent)
-
* 播放歌词的时间加10毫秒。currentTimeMill = currentTimeMill + 10;
-
* 10毫秒后再次调用回调函数updateTimeCallback:handler.postDelayed(updateTimeCallback, 10);
-
*
-
* */
-
-
class UpdatetimeCallback implements Runnable {
-
Queue times = null;
-
Queue messages = null;
-
public UpdatetimeCallback(ArrayList<Queue> queues) {
-
// 从ArrayList当中取出相应的对象
-
times = queues.get(0);
-
messages = queues.get(1);
-
/*这里整死哥 了,定义成局域变量
-
* Queue times = queues.get(0);
-
* Queue messages =queues.get(1);
-
*/
-
}
-
-
@Override
-
public void run() {
-
// 计算偏移量,也就是说从开始播放Mp3到现在为止,共消耗了多少时间,以毫秒为单位
-
long offset = System.currentTimeMillis() - begin;
-
if (times.size() > 0 && messages.size() > 0) {
-
if (currentTimeMill == 0) {
-
nextTimeMill = (Long) times.poll();// poll()来获取并移出元素
-
message = (String) messages.poll();
-
}
-
if (offset >= nextTimeMill) {
-
Intent intent = new Intent();
-
intent.setAction(AppConstant.LRC_MESSAGE_ACTION);
-
intent.putExtra("lrcMessage", message);
-
sendBroadcast(intent);
-
message = (String) messages.poll();
-
nextTimeMill = (Long) times.poll();
-
}
-
currentTimeMill = currentTimeMill + 10;//从播放歌词到现在经过的时间。 这个变量其实没什么用
-
handler.postDelayed(updateTimeCallback, 10);
-
}
-
}
-
}
-
-
/* mHandler=new Handler();
-
mHandler.post(new Runnable(){
-
void run(){
-
//执行代码...
-
}
-
});
-
这个线程其实是在UI线程之内运行的,并没有新建线程。
-
常见的新建线程的方法是:
-
Thread thread = new Thread();
-
thread.start();
-
HandlerThread thread = new HandlerThread("string");
-
thread.start();
-
详细出处参考:*/
-
}
阅读(861) | 评论(0) | 转发(0) |