关于调用频繁调用MediaPlayer播放音乐导致ANR的解决办法

本来想建一个demo工程上传到git上面,但是由于只是简单的2个类,想想还是算了吧。
这次分为播放手机自身音乐以及播放网络音乐的处理办法。有想测试的可以拷贝进去搞一个RecyclerView里面弄一些网络数据来测试一下,应该还是顺畅的(自带丝滑功能)
就是2个类,权当作一个笔记吧。。。。。。。。。。。

先献上本地音乐使用的PlayLocalMusicController

package com.pd.plugin.pd.led.controller;

import android.media.AudioManager;
import android.media.MediaPlayer;

/**
 * 播放本地音乐使用<br>
 * <font color="red">播放bug</font>
 * 多次按照顺序点击播放会出现(播放停滞状态,需要暂停播放歌曲然后在播放一次才能解决)bug,暂时没找到解决办法(貌似已经解决了)
 * Created by Tangxb on 2016/7/5.
 */
public class PlayLocalMusicController {
    private MediaPlayer mediaPlayer = new MediaPlayer();
    private int position;
    private PlayMusicCompleteListener listener;

    public interface PlayMusicCompleteListener {
        void playMusicComplete(int position);
    }

    public void playMusic(final int position, final String url, final int currentPlayTime
            , final PlayMusicCompleteListener listener) {
        try {
            this.position = position;
            this.listener = listener;
            mediaPlayer.reset();
            mediaPlayer.setDataSource(url);
            mediaPlayer.setLooping(false);
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer player) {
                    mediaPlayer.seekTo(currentPlayTime);
                }
            });
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer player) {
                    listener.playMusicComplete(position);
                    stopMediaPlayer();
                }
            });
            mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(MediaPlayer player, int what, int extra) {
                    stopMediaPlayer();
                    return false;
                }
            });
            mediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
                public void onSeekComplete(MediaPlayer player) {
                    mediaPlayer.start();
                }
            });
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public int getCurrentPlayTime() {
        if (mediaPlayer != null) {
            return mediaPlayer.getCurrentPosition();
        }
        return 0;
    }

    public void stopMediaPlayer() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
        }
    }

    /**
     * 页面被挂起的时候调用
     */
    public void onStopForMediaPlayer() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
        }
        if (listener != null) {
            listener.playMusicComplete(position);
        }
    }

    public void releaseMediaPlayer() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
}

下面是网络播放使用的LMediaPlayerManger

package com.pd.plugin.pd.led;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;

/**
 * 单例的MediaPlayer操作,适用于播放网络歌曲的时候使用;播放本地歌曲请使用{@link com.pd.plugin.pd.led.controller.PlayLocalMusicController}
 * 参考博客链接 http://blog.csdn.net/u011516685/article/details/50510902
 * 这里注意使用stop和prepareAsync是耗时操作需要在线程里面执行,同时由于stop多次出错之后之前的MediaPlayer不能够被正常使用,所以这里才会采取每次新建一个MediaPlayer实例
 * 这里PlayMusicCompleteListener没有使用弱引用,因为在应用程序里面会存在被GC掉,所以这里使用Handler来避免内存泄露的方式实现
 * Created by Tangxb on 2016/9/1.
 */
public class LMediaPlayerManger {
    private static LMediaPlayerManger instance;
    private MediaPlayer mediaPlayer;
    private HandlerThread playHandlerThread;
    private Handler playHandler;
    /**
     * 播放
     */
    private static final int PLAY = 101;
    /**
     * 停止
     */
    private static final int STOP = 102;
    /**
     * 释放
     */
    private static final int RELEASE = 103;
    /**
     * 界面不可见
     */
    private static final int ONSTOP = 104;
    private Handler handler;
    private int position;
    private String url;
    private PlayMusicCompleteListener listener;

    /**
     * 播放一首完成的回调
     */
    public interface PlayMusicCompleteListener {
        void playMusicComplete(int position);
    }

    private void createHandlerThreadIfNeed() {
        if (playHandlerThread == null) {
            playHandlerThread = new HandlerThread("playHandlerThread");
            playHandlerThread.start();
        }
    }

    private void createHandlerIfNeed() {
        if (playHandler == null) {
            playHandler = new Handler(playHandlerThread.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case PLAY:
                            playMusic01();
                            break;
                        case STOP:
                            stopMediaPlayer02();
                            break;
                        case RELEASE:
                            releaseMediaPlayer02();
                            break;
                        case ONSTOP:
                            stopMediaPlayer03();
                            break;
                    }
                }
            };
        }
    }

    private void createPlayerIfNeed() {
        if (mediaPlayer == null) {
            mediaPlayer = new MediaPlayer();
        }
    }

    private LMediaPlayerManger() {
        handler = new Handler(Looper.getMainLooper());
        createHandlerThreadIfNeed();
        createHandlerIfNeed();
    }

    public static LMediaPlayerManger getInstance() {
        if (instance == null) {
            instance = new LMediaPlayerManger();
        }
        return instance;
    }

    public void playMusic(int position, String url, PlayMusicCompleteListener listener) {
        this.position = position;
        this.url = url;
        this.listener = listener;
        playHandler.sendEmptyMessageDelayed(PLAY, 0L);
    }

    public void playMusic01() {
        createPlayerIfNeed();
        playMusic02(url);
    }

    public void playMusic02(String url) {
        try {
            mediaPlayer.reset();
            mediaPlayer.setDataSource(url);
            mediaPlayer.setLooping(false);
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer player) {
                    if (mediaPlayer != null) {
                        mediaPlayer.start();
                    }
                }
            });
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer player) {
                    playMusicComplete();
                    stopMediaPlayer();
                }
            });
            mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(MediaPlayer player, int what, int extra) {
                    stopMediaPlayer();
                    return false;
                }
            });
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void stopMediaPlayer() {
        playHandler.sendEmptyMessage(STOP);
    }

    public void onStopForMediaPlayer() {
        playHandler.sendEmptyMessage(ONSTOP);
    }

    /**
     * 这里需要注意设置setOnPreparedListener和setOnCompletionListener为null,因为不设置它会调用上一个已经设置好的回调(经过测试,请注意)
     */
    public void stopMediaPlayer02() {
        if (mediaPlayer != null) {
            mediaPlayer.setOnPreparedListener(null);
            mediaPlayer.setOnCompletionListener(null);
            try {
                mediaPlayer.stop();
            } catch (IllegalStateException e) {

            }
        }
        mediaPlayer = null;
    }

    /**
     * 这里需要注意设置setOnPreparedListener和setOnCompletionListener为null,因为不设置它会调用上一个已经设置好的回调(经过测试,请注意)
     */
    public void stopMediaPlayer03() {
        stopMediaPlayer02();
        playMusicComplete();
    }

    /**
     * 播放完成,需要在主线程里面更新UI
     */
    public void playMusicComplete() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (listener != null) {
                    listener.playMusicComplete(position);
                }
            }
        });
    }

    public void releaseMediaPlayer() {
        playHandler.sendEmptyMessage(RELEASE);
    }

    public void releaseMediaPlayer02() {
        if (mediaPlayer != null) {
            try {
                mediaPlayer.stop();
                mediaPlayer.release();
            } catch (IllegalStateException e) {

            }
        }
        mediaPlayer = null;
        // 避免内存泄露
        listener = null;
        handler.removeCallbacksAndMessages(null);
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值