IjkMediaPlayer.reset()耗时的一个解决方案

本文主要记录一些零碎的东西

使用IjkMediaPlayer 播放音乐时,快速点击切换播放的音乐,会出各种问题,本文给出一个修复方案,仅仅个人测试OK。

ijkplayer地址:https://github.com/Bilibili/ijkplayer

看看效果,不卡UI线程

IjkMediaPlayer.reset()耗时的一个解决方案_第1张图片

解决思路:

问题:IjkMediaPlayer reset() 耗时,release() 在音频未加载完时,也是耗时操作

解决:使用两个队列,一个存放可以使用的IjkMediaPlayer,一个存放待 释放的IjkMediaPlayer,每次调用findAvailableMediaPlayer()都可取出一个可使用的播放器

待释放播放器在线程里 reset。

使用:

findAvailableMediaPlayer();
mMediaPlayer.setDataSource(url);
mMediaPlayer.prepareAsync();

关键方法:

private final static int MEDIA_PLAYER_NUM = 4;
    private ExecutorService mExecutorService = Executors.newScheduledThreadPool(MEDIA_PLAYER_NUM);
    private Queue mMediaPlayerQueue = new ArrayDeque<>();
    private Queue mRecycleQueue = new ArrayDeque<>();
    private IjkMediaPlayer mMediaPlayer;
    private final Object mAvailableLocker = new Object();
    /**
     * create a new player and release current
     * mMediaPlayer.reset(); cost too much time
     * release() 在音频未加载完时,也是耗时操作
     * 但是用户快速点击切换播放音乐,有问题
     *
     * 没有到限制播放器数量,直接新建
     * 存在 可用队列 为空 的情况,即所有的 player 都在 reset ,此时直接新建
     *
     */
    private void findAvailableMediaPlayer() {
        try {
            if (currentPlayerNumLegal() || mMediaPlayerQueue.isEmpty()) {
                D.i("create a new media player available size: " + mMediaPlayerQueue.size() + " recycle size: " + mRecycleQueue.size());
                IjkMediaPlayer mediaPlayer = new IjkMediaPlayer();
                mediaPlayer.setLooping(true);
                mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                mediaPlayer.setOnPreparedListener(mPreparedListener);
                mediaPlayer.setOnCompletionListener(mCompletionListener);
                queueAvailableMediaPlayer(mediaPlayer);
            }
            if (mMediaPlayer != null) {
                // 加入回收队列,待处理 释放
                synchronized (mAvailableLocker) {
                    mRecycleQueue.add(mMediaPlayer);
                }
            }
            // 此处 mMediaPlayer not null
            D.i("availble media player size: " + mMediaPlayerQueue.size());
            synchronized (mAvailableLocker) {
                mMediaPlayer = mMediaPlayerQueue.poll();
            }

            if(mRecycleQueue.size() > 0) {
                mExecutorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        IjkMediaPlayer player;
                        synchronized (mAvailableLocker) {
                            player = mRecycleQueue.poll();
                        }
                        D.i("media player reset... ");
                        player.reset();
                        D.i("media player reset done... ");
                        queueAvailableMediaPlayer(player);
                    }
                });
            }

        } catch (Exception e) {
            D.e("media player error: " + e.getMessage());
        }
    }

    private boolean currentPlayerNumLegal(){
        synchronized (mAvailableLocker) {
            return MEDIA_PLAYER_NUM > mMediaPlayerQueue.size() + mRecycleQueue.size();
        }
    }

    private void queueAvailableMediaPlayer(IjkMediaPlayer player){
        synchronized (mAvailableLocker) {
            mMediaPlayerQueue.add(player);
            D.i("media player size: " + mMediaPlayerQueue.size());
        }
    }

    private IMediaPlayer.OnPreparedListener mPreparedListener =
            new IMediaPlayer.OnPreparedListener() {

                @Override
                public void onPrepared(IMediaPlayer mp) {
                    D.i("media player prepared ...");
                    mp.start();
                }
            };

    private IMediaPlayer.OnCompletionListener mCompletionListener =
            new IMediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(IMediaPlayer mp) {
                    D.i("media player completed ...");
                }
            };

你可能感兴趣的:(IjkMediaPlayer.reset()耗时的一个解决方案)