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

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

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

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

看看效果,不卡UI线程


解决思路:

问题: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<IjkMediaPlayer> mMediaPlayerQueue = new ArrayDeque<>();
    private Queue<IjkMediaPlayer> 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 ...");
                }
            };

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值