NotificationPlayer.java
定义一个播放Notification声音的player,本质上仍然是一个MediaPlayer,这个是多线程编程的很好的例子
public class NotificationPlayer implements OnCompletionListener {
//发送播放和停止的cmd
private static final int PLAY = 1;
private static final int STOP = 2;
//对于多线程处理来说,这个class用来线程之间传递数据
private static final class Command {
int code;
Context context;
Uri uri;
boolean looping;
int stream;
long requestTime;
public String toString() {
return "{ code=" + code + " looping=" + looping + " stream=" + stream
+ " uri=" + uri + " }";
}
}
//播放类构造函数
public NotificationPlayer(String tag) {
if (tag != null) {
mTag = tag;
} else {
mTag = "NotificationPlayer";
}
}
public void play(Context context, Uri uri, boolean looping, int stream) {
//创建用于进程之间传递数据的类。前面说的那个中间class
Command cmd = new Command();
//初始化信息
cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = PLAY;
cmd.context = context;
cmd.uri = uri;
cmd.looping = looping;
cmd.stream = stream;
synchronized (mCmdQueue) {
//开始另外一个线程,用来解析用户设置cmd,然后才决定是play还是stop
enqueueLocked(cmd);
mState = PLAY;
}
}
//这表明CmdThread就是一个thread
private final class CmdThread extends java.lang.Thread {
CmdThread() {
super("NotificationPlayer-" + mTag);
}
public void run() {
while (true) {
Command cmd = null;
synchronized (mCmdQueue) {
//这一步很巧妙,直接用队列中删除返回删除数据的引用来获取刚才在play中设置的信息
cmd = mCmdQueue.removeFirst();
}
switch (cmd.code) {
case PLAY:
startSound(cmd);
break;
//主要是用户发出停止的命令的操作--非正常播放结束stop
case STOP:
……
//强制停止要释放focus
mAudioManager.abandonAudioFocus(null);
break;
}
//处理之后要释放wakelock
synchronized (mCmdQueue) {
if (mCmdQueue.size() == 0) {
mThread = null;
releaseWakeLock();
return;
}
}
}
}
}//end ofCmdThread
private void startSound(Command cmd) {
try {
if((mLooper != null)
&& (mLooper.getThread().getState() != Thread.State.TERMINATED)) {
mLooper.quit();
}
mCompletionThread = new CreationAndCompletionThread(cmd);
//开启播放线程
synchronized(mCompletionThread) {
mCompletionThread.start();
mCompletionThread.wait();
}
}
}
private final class CreationAndCompletionThread extends Thread {
public Command mCmd;
public CreationAndCompletionThread(Command cmd) {
super();
mCmd = cmd;
}
public void run() {
try {
//设置播放信息,并开始播放
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(mCmd.stream);
player.setDataSource(mCmd.context, mCmd.uri);
player.setLooping(mCmd.looping);
player.prepare();
if ((mCmd.uri != null) && (mCmd.uri.getEncodedPath() != null)
&& (mCmd.uri.getEncodedPath().length() > 0)) {
if (mCmd.looping) {
audioManager.requestAudioFocus(null, mCmd.stream,
AudioManager.AUDIOFOCUS_GAIN);
} else {
audioManager.requestAudioFocus(null, mCmd.stream,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
}
}
//这一步是必须的,要释放focus
player.setOnCompletionListener(NotificationPlayer.this);
player.start();
}
}
}
public void onCompletion(MediaPlayer mp) {
if (mAudioManager != null) {
mAudioManager.abandonAudioFocus(null);
}
}
}