Android L**MM music Service笔记

(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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值