美文网首页Android进阶
MediaPlayer加载不同的资源文件 重复播放

MediaPlayer加载不同的资源文件 重复播放

作者: 2f479b1467f1 | 来源:发表于2017-04-28 09:57 被阅读72次

    MediaPlayer加载不同的资源文件 重复播放

    需求是这样,有许多本地的声音文件,放在raw资源文件内,点击不同的按钮会调用不同的声音播放。并且如果在上一次声音没有播放完成之前就点击另外一个按钮,则会中断之前的播放,直接播放当前的声音文件。

    关于MediaPlayer的加载方法有以下几种:
    如何设置要播放的文件:
    MediaPlayer要播放的文件主要包括3个来源:
    a. 用户在应用中事先自带的resource资源
    例如:MediaPlayer.create(this, R.raw.test);
    b. 存储在SD卡或其他文件路径下的媒体文件
    例如:mp.setDataSource("/sdcard/test.mp3");
    c. 网络上的媒体文件
    例如:mp.setDataSource("http://www.citynorth.cn/music/confucius.mp3");

    我们是选择资源文件,所以使用第一种方法。

    根据阅读MediaPlayer的源码,得知用此种方法每次都要new 一个MediaPlayer对象,这样效率很低下

    以下是系统创建MediaPlayer 的方法:
    public static MediaPlayer create(Context context, int resid,
    AudioAttributes audioAttributes, int audioSessionId) {
    try {
    AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
    if (afd == null) return null;

            MediaPlayer mp = new MediaPlayer();
    
            final AudioAttributes aa = audioAttributes != null ? audioAttributes :
                new AudioAttributes.Builder().build();
            mp.setAudioAttributes(aa);
            mp.setAudioSessionId(audioSessionId);
    
            mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            afd.close();
            mp.prepare();
            return mp;
        } catch (IOException ex) {
            Log.d(TAG, "create failed:", ex);
            // fall through
        } catch (IllegalArgumentException ex) {
            Log.d(TAG, "create failed:", ex);
           // fall through
        } catch (SecurityException ex) {
            Log.d(TAG, "create failed:", ex);
            // fall through
        }
        return null;
    }
    

    看到核心创建代码为
    AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
    if (afd == null) return null;

            MediaPlayer mp = new MediaPlayer();
    
            final AudioAttributes aa = audioAttributes != null ? audioAttributes :
                new AudioAttributes.Builder().build();
            mp.setAudioAttributes(aa);
            mp.setAudioSessionId(audioSessionId);
    
            mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    

    于是想到复写这个方法,因为Mediaplayer已经创建 ,所以在第二次设置时不需要设置AudioAttributers,可以直接根据资源文件,调用setDataSource方法:

    public static MediaPlayer getMediaPlayer(Context context, int resid) {
    AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
    if (afd == null) return null;
    if (null == mMediaPlayer) {
    mMediaPlayer = MediaPlayer.create(context, resid);
    mMediaPlayer.setOnCompletionListener(mListener);
    mMediaPlayer.setOnErrorListener(mErroListener);
    return mMediaPlayer;
    }
    try {
    mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    afd.close();
    mMediaPlayer.prepare();
    mMediaPlayer.setOnCompletionListener(mListener);
    mMediaPlayer.setOnErrorListener(mErroListener);
    return mMediaPlayer;
    } catch (IOException ex) {
    // fall through
    } catch (IllegalArgumentException ex) {
    // fall through
    } catch (SecurityException ex) {
    // fall through
    }
    return null;
    }

    可是这种方法依然不行,系统会抛出异常,查阅资料是因为再次调用的时候,C++底层认为这个Player和之前的ID不一样所以抛出异常,此时如果调用isPlaying方法也会报出同样的错误,所以还是用了最进本的方法,每次创建一个MediaPlayer,用完后release掉:
    public class SoundManagerUtil {

    private static MediaPlayer mMediaPlayer;
    
    private static MediaPlayer.OnCompletionListener mListener = new MediaPlayer.OnCompletionListener() {
    
        @Override
        public void onCompletion(MediaPlayer mp) {
            stopAndReleaseMeiaPlayer();
        }
    };
    
    private static MediaPlayer.OnErrorListener mErroListener = new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            mMediaPlayer.reset();
            return false;
        }
    };
    
    private static void stopAndReleaseMeiaPlayer() {
        mMediaPlayer.stop();
        mMediaPlayer.release();
        mMediaPlayer = null;
    }
    
    public static void sendSound(Context context, int soundName) {
        if (null == mMediaPlayer) {
            getmMediaPlayerByName(context, soundName);
        } else {
            //mediaplayer对象的状态和native的对象状态发生了不一致
            try {
                if (mMediaPlayer.isPlaying()) {
                    stopAndReleaseMeiaPlayer();
                }
            } catch (Exception e) {
            }
        }
        getmMediaPlayerByName(context, soundName);
        if (null == mMediaPlayer) {
            Log.e("kevin", "cant find soundName");
            return;
        }
        mMediaPlayer.start();
    
    }
    
    public static void getmMediaPlayerByName(Context context, int soundName) {
        switch (soundName) {
            case Constance.BANK_CARD_RESERVATION_PHONE_NUMBER:
                mMediaPlayer = getMediaPlayer(context, R.raw.bank_card_reservation_phone_number_tips);
                break;
            case Constance.BORROW_ENTER_PHONE_NUMBER:
                mMediaPlayer = getMediaPlayer(context, R.raw.borrow_enter_phone_number);
                break;
            case Constance.BORROWING_QUOTA:
                mMediaPlayer = getMediaPlayer(context, R.raw.borrowing_quota);
                break;
            case Constance.ENTER_PHONE_NUMBER:
                mMediaPlayer = getMediaPlayer(context, R.raw.enter_phone_number_login);
                break;
            case Constance.ENTRY_SYSTEM:
                mMediaPlayer = getMediaPlayer(context, R.raw.entry_system);
                break;
            case Constance.FACE_CHECK_TITLE:
                mMediaPlayer = getMediaPlayer(context, R.raw.face_check_titile);
                break;
            case Constance.ID_CARD_PLACEMENT_INSTRUCTIONS:
                mMediaPlayer = getMediaPlayer(context, R.raw.id_card_placement_instructions);
                break;
            case Constance.ID_INFORMATION_SURE:
                mMediaPlayer = getMediaPlayer(context, R.raw.id_information_sure);
                break;
            case Constance.LOGIN_SUCCESS:
                mMediaPlayer = getMediaPlayer(context, R.raw.login_success);
                break;
            case Constance.PUT_BANK_CARD:
                mMediaPlayer = getMediaPlayer(context, R.raw.put_bank_card);
                break;
        }
    }
    
    public static MediaPlayer getMediaPlayer(Context context, int resid) {
        mMediaPlayer = MediaPlayer.create(context, resid);
        mMediaPlayer.setOnCompletionListener(mListener);
        mMediaPlayer.setOnErrorListener(mErroListener);
        return mMediaPlayer;
    }
    

    }

    相关文章

      网友评论

        本文标题:MediaPlayer加载不同的资源文件 重复播放

        本文链接:https://www.haomeiwen.com/subject/pysozttx.html