(1)首先AndroidManifest.xml
要添加service
<!-- Music broadcast module Service -->
<service
android:name="com.jrm.localmm.ui.music.MediaService"
android:enabled="true" >
</service>
(2)添加aidl文件作为进程管道的声明
<1>music 的一些状态方法声明,方便client端实现播放,暂停,下一曲,seek的操作
package com.jrm.localmm.ui.music;
import com.jrm.localmm.ui.music.IMusicStatusListener;
interface IMediaService {
void stop();
void pause();
void initPlayer(String path);
void next(String path);
void continuePlay();
void playerToPosiztion(int position);
boolean isPlaying();
String getAudioCodecType();
long getCurrentPosition();
long getDuration();
int getAudioSessionId();
void setMusicStatusListener(IMusicStatusListener musicStatusListener);
}
<2>
然后是music listener,做法callback去使用,就是server端去call client端的管道
package com.jrm.localmm.ui.music;
interface IMusicStatusListener {
/**
* when music play Exception,callback
*/
void musicPlayException(String errMessage);
/**
* when music play error,OnError()处理,callback
* @param errMessage
*/
boolean musicPlayErrorWithMsg(String errMessage);
/**
* handle song spectrum (处理音乐频谱)
*/
void handleSongSpectrum();
/**
* when handle music info,callback
*/
void handleMessageInfo(String strMessage);
/**
* when music prepares,callback
*/
void musicPrepared();
/**
* when music completes,callback
*/
void musicCompleted();
/**
* when music seeks completed,callback
*/
void musicSeekCompleted();
}
(3)在一个musicUtil里面写bindservice 和 unbindService的 一些可复制的code
public class MusicUtils {
private static final String TAG = "MusicUtils";
public static IMediaService sService = null;
private static final Uri sArtworkUri = Uri
.parse("content://media/external/audio/albumart");
private static final BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();
private static HashMap<Context, ServiceBinder> sConnectionMap = new HashMap<Context, ServiceBinder>();
public static class ServiceToken {
ContextWrapper mWrappedContext;
ServiceToken(ContextWrapper context) {
mWrappedContext = context;
}
}
public static ServiceToken bindToService(Activity context,
ServiceConnection callback) {
Activity realActivity = context.getParent();
if (realActivity == null) {
realActivity = context;
}
ContextWrapper cw = new ContextWrapper(realActivity);
cw.startService(new Intent(cw, MediaService.class));
ServiceBinder sb = new ServiceBinder(callback);
if (cw.bindService((new Intent()).setClass(cw, MediaService.class), sb,
0)) {
sConnectionMap.put(cw, sb);
return new ServiceToken(cw);
}
Log.e(TAG, "Failed to bind to service");
return null;
}
public static void unbindFromService(ServiceToken token) {
if (token == null) {
Log.e(TAG, "Trying to unbind with null token");
return;
}
ContextWrapper cw = token.mWrappedContext;
ServiceBinder sb = sConnectionMap.remove(cw);
if (sb == null) {
Log.e(TAG, "Trying to unbind for unknown Context");
return;
}
cw.unbindService(sb);
// if (sConnectionMap.isEmpty()) {
// sService = null;
// }
}
private static class ServiceBinder implements ServiceConnection {
ServiceConnection mCallback;
ServiceBinder(ServiceConnection callback) {
mCallback = callback;
}
public void onServiceConnected(ComponentName className,
android.os.IBinder service) {
sService = IMediaService.Stub.asInterface(service);
if (mCallback != null) {
mCallback.onServiceConnected(className, service);
}
}
public void onServiceDisconnected(ComponentName className) {
if (mCallback != null) {
mCallback.onServiceDisconnected(className);
}
sService = null;
}
}
(4)然后是server端的service的code
声明一个MediaService的类继承service,onBind要继承并且实现,另外在onCreat的时候要创建player
*/
public class MediaService extends Service {
private static final String TAG = "MediaService";
private final IBinder mBinder = new ServiceStub(this);
// mediaplayer
private MMediaPlayer player = null;
private IMusicStatusListener mMusicStatusListener;
private int mDuration;
// all possible internal states
private static final int STATE_ERROR = -1;
private static final int STATE_IDLE = 0;
private static final int STATE_PREPARING = 1;
private static final int STATE_PREPARED = 2;
private static final int STATE_PLAYING = 3;
private static final int STATE_PAUSED = 4;
private static final int STATE_PLAYBACK_COMPLETED = 5;
private int mCurrentState = STATE_IDLE;
@SuppressWarnings("unused")
private int mTargetState = STATE_IDLE;
private boolean mCanPause;
private boolean mCanSeekBack;
private boolean mCanSeekForward;
// recording the seek position while preparing
@SuppressWarnings("unused")
private int mSeekWhenPrepared;
// ///
// Service Class rewrite area
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
if (player == null) {
player = new MMediaPlayer();
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand player");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy player");
stop();
}
以下代码省略〉〉〉
(5)然后是创建管道类使得service 和client可以交互
<1>这里是client端向service端发出请求的一些方法
也就是要music 暂停,播放,下一曲等的方法
创建一个ServiceStub实现aidl里面的管道方法。并且在这里使用弱引用来保存service对象
private class ServiceStub extends IMediaService.Stub {
WeakReference<MediaService> mService;
ServiceStub(MediaService service) {
mService = new WeakReference<MediaService>(service);
}
public void stop() {
mService.get().stop();
}
public void pause() {
mService.get().pause();
}
public void initPlayer(String path) {
Log.d(TAG, "initPlayer, current thread id : "
+ Thread.currentThread().getId());
String musicPath = path;
if (Tools.isSambaPlaybackUrl(path)) {
Log.i(TAG,"HttpBean.setmSmbUrl path:"+path);
HttpBean.setmSmbUrl(path);
Log.i(TAG,"before convertSambaToHttpUrl's path:"+path);
String sambaPath = HttpBean.convertSambaToHttpUrl(path);
Log.i(TAG,"convertSambaToHttpUrl's result sambaPath:"+sambaPath);
musicPath = sambaPath;
}
Log.i(TAG,"musicPath:"+musicPath);
mService.get().openPlayer(musicPath);
}
public void next(String path) {
mService.get().next(path);
}
public void continuePlay() {
mService.get().start();
}
public void playerToPosiztion(int position) {
mService.get().seekTo(position);
}
public boolean isPlaying() {
if (mService.get() != null) {
return mService.get().isPlaying();
} else {
return false;
}
}
public String getAudioCodecType() {
if (player != null) {
return player.getAudioCodecType();
}
return null;
}
public long getCurrentPosition() {
return mService.get().getCurrentPosition();
}
public long getDuration() {
return mService.get().getDuration();
}
public int getAudioSessionId() {
return mService.get().getAudioSessionId();
}
public void setMusicStatusListener(
IMusicStatusListener musicStatusListener)
throws RemoteException {
mMusicStatusListener = musicStatusListener;
}
}
<2>接着便是service向client回调的code的实现了。毕竟adil只是声明接口而已
private IMusicStatusListener musicStatusListener = new IMusicStatusListener.Stub() {
@Override
public void musicSeekCompleted() throws RemoteException {
Log.d(TAG, "IMusicStatusListener.Stub, musicSeekCompleted");
}
@Override
public void musicPrepared() {
// Ready to play, get countTime and audioSessionId
// processPlayPrepare();
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "IMusicStatusListener.Stub, musicPrepared");
musicPlayHandle.sendEmptyMessage(HANDLE_MESSAGE_MUSIC_PREPARE);
}
}).start();
}
@Override
public boolean musicPlayErrorWithMsg(String errMessage)
throws RemoteException {
Log.d(TAG, "IMusicStatusListener.Stub, musicPlayErrorWithMsg");
exceptionProcess(errMessage);
musicPlayHandle.removeMessages(MusicPlayerActivity.HANDLE_MESSAGE_SEEKBAR_UPDATE);
return true;
}
@Override
public void musicPlayException(String errMessage)
throws RemoteException {
Log.d(TAG, "IMusicStatusListener.Stub, musicPlayException");
exceptionProcess(errMessage);
musicPlayHandle.removeMessages(MusicPlayerActivity.HANDLE_MESSAGE_SEEKBAR_UPDATE);
}
@Override
public void musicCompleted() throws RemoteException {
Log.d(TAG, "IMusicStatusListener.Stub, musicCompleted");
musicPlayHandle.removeMessages(MusicPlayerActivity.HANDLE_MESSAGE_SEEKBAR_UPDATE);
if(!isErrorDialogShow ){
processPlayCompletion();
}
}
@Override
public void handleSongSpectrum() throws RemoteException {
// Spectrum processing
Log.d(TAG, "IMusicStatusListener.Stub, handleSongSpectrum");
}
@Override
public void handleMessageInfo(String strMessage) throws RemoteException {
if(strMessage == getResources().getString(R.string.video_media_error_video_unsupport)){
isVideoSupport = false;
}
if(strMessage == getResources().getString(R.string.video_media_error_audio_unsupport)){
isAudioSupport = false;
Toast toast = ToastFactory.getToast(MusicPlayerActivity.this, strMessage,
Gravity.CENTER);
toast.show();
}
if (!isVideoSupport && !isAudioSupport) {
if(musicList.size() <= 1){
exitMusicPaly();
}else{
musicPlayHandle
.removeMessages(MusicPlayerActivity.HANDLE_MESSAGE_SEEKBAR_UPDATE);
processPlayCompletion();
}
}
Log.d(TAG, "IMusicStatusListener.Stub, handleMessageInfo");
}
};
(6)然后就是创建activity的时候怎么开启service呢?
<1>必须先要创建一个serviceConnection的类。
并且实现连接上的回调函数,断开的回调函数
private ServiceConnection musicServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName classname, IBinder obj) {
mService = IMediaService.Stub.asInterface(obj);
Log.i(TAG, "ServiceConnection:::onServiceConnected mService:" + mService);
if (mService != null) {
try {
mService.setMusicStatusListener(musicStatusListener);
} catch (RemoteException e) {
e.printStackTrace();
}
musicPlayHandle.sendEmptyMessage(HANDLE_MESSAGE_SERVICE_START);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "ServiceConnection:::onServiceDisconnected mService:" + mService);
mService = null;
}
};
<2>
在MusicActivity的onCreate里面要创建一个ServiceToken的东东
ServiceToken stToken = MusicUtils.bindToService(MusicPlayerActivity.this,musicServiceConnection);
这里Bind上之后 会和(3)的code进行一系列的交互,最终连接上了又回调到musicServiceConnection的onServiceConnect里面来了。
这里就准备开始向service请求开始播放music啦啦啦。
mService.initPlayer(path);
(6)既然上面都有开始,到连上,到工作的flow,那最后怎么断开呢
首先要stopService
private void stopMusicService() {
Intent i = new Intent(MusicPlayerActivity.this, MediaService.class);
stopService(i);
}
然后要unbindService
if (stToken != null) {
MusicUtils.unbindFromService(stToken);
}
最后,又附上一篇好文哈:http://www.cnblogs.com/newcj/archive/2011/05/30/2061370.html