Android进阶

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

2017-04-28  本文已影响72人  2f479b1467f1

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;
}

}

上一篇下一篇

猜你喜欢

热点阅读