当前位置: 首页 > 工具软件 > VideoCache > 使用案例 >

IjkPlayer+AndroidVideoCache 实现音乐播放

章兴发
2023-12-01

 IjkPlayer 实现音乐播放(进度条、缓存、是否正在缓冲等) 

枚举:

public enum AudioPlayEnum {
    /**播放空闲*/
    PLAYER_FREE,
    /**预缓冲,准备播放中*/
    PLAYER_PREPARING,
    /**播放中*/
    PLAYER_PLAYING,
    /**播放完毕*/
    PLAYER_COMPLETE,
    /**播放暂停*/
    PLAYER_PAUSE,
    /**播放错误*/
    PLAYER_ERROR
}

回调接口

public interface AudioPlayerEvent {
    /**
     * 缓存更新
     * */
    void onBufferingUpdate(int percent);
    /**
     * 是否正在缓冲*/
    void onBuffering(boolean isBuffering);
    /**
     * 播放进度*/
    void onPlayProgress(long duration,long currPosition);

    /**
     * 播放状态改变
     * @param mStatus 状态
     */
    void onStatusChange(AudioPlayEnum mStatus,int currPlayPotion);
}

 

抽象类

public abstract class MyAbstractAudioPlayer {

    AudioPlayerEvent mAudioPlayerEvent;
    /**
     * 暂停之后调用,接着上一次播放
     */
    public abstract void reStart();
    /**
     * 带资源播放,播放当前资源
     * @param path path
     */
    public abstract void start(String path);

    /**
     * 将整个列表添加到播放列表,如果是未播放状态,则播放第一个
     * @param pathList 资源列表
     */
    public abstract void start(List<String> pathList);

    /**
     * 播放事件监听器
     * @param event 时间
     */
    public abstract void setAudioPlayerListener(AudioPlayerEvent event);

    /**
     * 暂停
     */
    public abstract void pause();

    /**
     * 暂停缓存
     * @param path 路径
     */
    public abstract void stopCacheAndShutdown(String path);

    /**
     * 下一首
     */
    public abstract void nextPlay();

    /**
     * 上一首
     */
    public abstract void prevPlay();

    /**
     * 是否正在播放
     * @return boolean
     */
    public abstract boolean isPlaying();

    /**
     * 当前播放状态
     * @return AudioPlayEnum
     */
    public abstract AudioPlayEnum getPlayerStatus();

    /**
     * 调整进度
     * @param time 时间
     */
    public abstract void seekTo(long time);

    /**
     * 拖动进度条,通知(防止拖动时Timmer跑进度条)
     */
    public abstract void seekStart();

    /**
     * 释放播放器
     */
    public abstract void release();

    /**
     * 获取当前播放的位置
     * @return 获取当前播放的位置
     */
    public abstract long getCurrentPosition();

    /**
     * 获取视频总时长
     * @return long
     */
    public abstract long getDuration();

    /**
     * 获取缓冲百分比
     * @return int
     */
    public abstract int getBufferedPercentage();
    /**
     * 设置列表是否循环播放
     * @param isLooping 循环
     */
    public abstract void setListLooping(boolean isLooping);
    /**
     * 设置是否单曲循环
     * @param isLooping 循环
     */
    public abstract void setSingleLooping(boolean isLooping);
}

 

该类实现对电话监听

/**
 * 自定义内部类对来电的电话状态进行监听
 * @author chenpin
 */
public class MyPhoneStateListener extends PhoneStateListener {
    private MyAudioManager mMyAudioManager;
    /**记录来电时,是否在播放状态,在电话空闲时恢复*/
    private boolean mAudioPlayingWhenCallRinging = false;

    MyPhoneStateListener(MyAudioManager mMyAudioManager) {
        this.mMyAudioManager = mMyAudioManager;
    }

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        super.onCallStateChanged(state, incomingNumber);
        if (mMyAudioManager == null) {
            return;
        }
        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
            case TelephonyManager.CALL_STATE_OFFHOOK:
                if(mMyAudioManager.isPlaying()){
                    mAudioPlayingWhenCallRinging = true;
                    mMyAudioManager.pause();
                }else{
                    mAudioPlayingWhenCallRinging = false;
                }
                break;
            case TelephonyManager.CALL_STATE_IDLE:
                //打完电话
                mMyAudioManager.reStart();
                break;
            default:
                break;
        }
    }
}

 

封装AndroidVideoCache缓存类

/**
 * @author chenpin
 */
public class AudioCacheManager {
    /**
     * 最大缓存容量
     */
    private static final long DEFAULT_MAX_SIZE = 200 * 1024 * 1024;
    /**
     *  最大缓存数量
     */
    private static final int DEFAULT_MAX_FILE_COUNT = 20;
    /**
     * SD卡APP保存文件名
     */
    private static final String SD_SAVE_PATH = "appName";
    @SuppressLint("SdCardPath")
    private static final String APP_SAVE_PATH = "/data/data/";

    private static final String SAVE_AUDIO_PATH = "audio_cache";


    private static AudioCacheManager mInstance;
    private static HttpProxyCacheServer mCacheServer;
    private CacheListener mCacheListener;

    public static AudioCacheManager getInstance(Context context) {
        Context applicationContext = context.getApplicationContext();
        if (null == mInstance) {
            synchronized (AudioCacheManager.class) {
                if (null == mInstance) {
                    mInstance = new AudioCacheManager(applicationContext);
                }
            }
        }
        return mInstance;
    }

    private AudioCacheManager(Context context) {
        File cacheDir = getCacheDirectory(context);
        Md5FileNameGenerator md5FileNameGenerator = new Md5FileNameGenerator();
        HttpProxyCacheServer.Builder builder = new HttpProxyCacheServer.Builder(context)
                .maxCacheFilesCount(DEFAULT_MAX_FILE_COUNT).cacheDirectory(cacheDir).fileNameGenerator(md5FileNameGenerator);
        mCacheServer = builder.build();
    }

    static HttpProxyCacheServer getProxy(Context context) {
        return mCacheServer == null ? (mCacheServer = newProxy(context)) : mCacheServer;
    }

    private static HttpProxyCacheServer newProxy(Context context) {
        return new HttpProxyCacheServer.Builder(context)
                .maxCacheSize(DEFAULT_MAX_SIZE)
                .build();
    }

    private File getCacheDirectory(Context context) {
        File cacheParentDir = getCacheParentDirectory(context);
        File cacheDir = new File(cacheParentDir, SAVE_AUDIO_PATH);
        if (!cacheDir.exists()) {
            cacheDir.mkdirs();
        }
        return cacheDir;
    }
    private File getCacheParentDirectory(Context context) {
        File appCacheDir = null;
        String externalStorageState;
        try {
            externalStorageState = Environment.getExternalStorageState();
        } catch (NullPointerException e) {
            externalStorageState = "";
        }
        if (MEDIA_MOUNTED.equals(externalStorageState)) {
            appCacheDir = getExternalCacheDir(context);
        }
        if (appCacheDir == null) {
            appCacheDir = context.getCacheDir();
        }
        if (appCacheDir == null) {
            String cacheDirPath = APP_SAVE_PATH
                    + context.getPackageName()
                    + File.separator+SAVE_AUDIO_PATH+File.separator;
            appCacheDir = new File(cacheDirPath);
        }
        return appCacheDir;
    }

    private static File getExternalCacheDir(Context context) {
        String pathPrix = Environment.getExternalStorageDirectory() + "/";
        File file = new File(pathPrix + SD_SAVE_PATH);
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }


    String getProxyUrl(String url) {
        return mCacheServer.getProxyUrl(url);
    }

    void registerCacheListener(String url, CacheListener listener) {
        mCacheListener = listener;
        mCacheServer.registerCacheListener(listener, url);
    }

    void unregisterCacheListener() {
        mCacheServer.unregisterCacheListener(mCacheListener);
    }
}

 

主要代码,音频管理类: 

//音频管理类
/**
 * 集成IjkPlayer音頻播放
 *
 * @author chenpin
 */
public class MyAudioManager extends MyAbstractAudioPlayer {
    public static final String TEST_MP3_URL = "http:XXX.mp3";

    /**
     * 定时器检测播放进度时间间隔
     */
    private final int TIMER_PROGRESS_INTERVAL = 200;
    /**
     * 最大连续播放错误数
     */
    private static final int MAX_CONTINUE_ERROR_NUM = 3;

    private IjkMediaPlayer mMediaPlayer;
    private Context mContext;
    private Context appContext;
    /**
     * 播放错误次数,连续三次错误,则不进行下一次播放了
     */
    private int mErrorPlayNum = 0;
    /**
     * 播放路径资源存储
     */
    private List<String> mDataSourceList = new ArrayList<>();
    /**
     * 播放位置存储
     */
    private int currPlayPotion = -1;
    /**
     * 是否列表循环播放
     */
    private boolean mListLooping = false;
    /**
     * 是否单曲循环
     */
    private boolean mSingleLooping = false;
    /**
     * 缓存百分比
     */
    private int mBufferedPercent;
    /**
     * 是否正在拖动进度条
     */
    private boolean mSeekTouch = false;
    /**
     * 监听播放器进度Timer以及Task
     */
    private Timer mProgressTimer;
    private TimerTask mProgressTask;
    private final Object mProgressLock = new Object();
    /**
     * 进度线程活动
     */
    private boolean mAudioStateAlive = true;
    /**
     * 音频缓存
     */
    private HttpProxyCacheServer mCacheServer;
    /**
     * 记录上一次播放进度,用于判断是否正在缓冲
     */
    private long prevPlayPosition;
    /**
     * 电话管理者对象
     */
    private TelephonyManager mTelephonyManager;
    /**
     * 电话状态监听者
     */
    private MyPhoneStateListener myPhoneStateListener;
    /**
     * 用于发送是否在缓冲的消息Handler
     */
    private Handler mBufferHandler = new Handler(Looper.getMainLooper());

    /**
     * 当前播放器状态
     * */
    private AudioPlayEnum mPlayerStatus = AudioPlayEnum.PLAYER_FREE;

    public MyAudioManager(Context context) {
        mContext = context;
        appContext = context.getApplicationContext();
        initPlayer();
    }

    private void initPlayer() {
        //初始化
        mMediaPlayer = new IjkMediaPlayer(mContext);
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        //缓存文件的路径
//        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "cache_file_path", path);
        //添加监听
        mMediaPlayer.setOnErrorListener(onErrorListener);
        mMediaPlayer.setOnCompletionListener(onCompletionListener);
        mMediaPlayer.setOnInfoListener(onInfoListener);
        mMediaPlayer.setOnBufferingUpdateListener(onBufferingUpdateListener);
        mMediaPlayer.setOnPreparedListener(onPreparedListener);
        //来电监听
        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        myPhoneStateListener = new MyPhoneStateListener(this);
        mTelephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
    }

    /**
     * 播放
     */
    private void prepareAsync(int position, String path) {
        try {
            mMediaPlayer.reset();
            sendPlayerStatus(AudioPlayEnum.PLAYER_PREPARING);
            mCacheServer = AudioCacheManager.getProxy(appContext);
            AudioCacheManager.getInstance(appContext).registerCacheListener(path, new CacheListener() {
                @Override
                public void onCacheAvailable(File file, String s, int i) {
                    mBufferedPercent = i;
                    if (mAudioPlayerEvent != null) {
                        mAudioPlayerEvent.onBufferingUpdate(mBufferedPercent);
                    }
                }
            });
            String proxyPath = AudioCacheManager.getInstance(appContext).getProxyUrl(path);
            if (mCacheServer.isCached(path)
                || proxyPath.startsWith("file://")
                || proxyPath.startsWith("/storage/emulated/0/")) {
                mBufferedPercent = 100;
                if (mAudioPlayerEvent != null) {
                    sendBufferingHandler(true, false);
                }
                //不要在这里发进度,上层调用不到duration,设置不了max
            } else {
                mBufferedPercent = 0;
                if (mAudioPlayerEvent != null) {
                    sendBufferingHandler(false, true);
                }
            }
            mMediaPlayer.setDataSource(proxyPath);
            mMediaPlayer.prepareAsync();
            currPlayPotion = position;
        } catch (Exception e) {
            e.printStackTrace();
            onErrorPlay();
        }
    }

    @Override
    public void reStart() {
        if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
            sendPlayerStatus(AudioPlayEnum.PLAYER_PLAYING);
            mMediaPlayer.start();
            synchronized (mProgressLock) {
                mProgressLock.notifyAll();
            }
        }
    }

    @Override
    public void start(String path) {
        if(!StringUtils.isEmpty(path)){
            List<String> pathList = new ArrayList<>();
            pathList.add(path);
            start(pathList);
        }
    }

    @Override
    public void start(List<String> pathList) {
        if (pathList == null || pathList.isEmpty()) {
            return;
        }
        mDataSourceList.clear();
        mDataSourceList.addAll(pathList);
        prepareAsync(0, mDataSourceList.get(0));
    }

    @Override
    public void setAudioPlayerListener(AudioPlayerEvent event) {
        this.mAudioPlayerEvent = event;
    }

    @Override
    public void pause() {
        try {
            if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
                sendBufferingHandler(true, false);
                sendPlayerStatus(AudioPlayEnum.PLAYER_PAUSE);
                mMediaPlayer.pause();
            }
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stopCacheAndShutdown(String path) {
        if (mCacheServer != null && !StringUtils.isEmpty(path)) {
            mCacheServer.stopCacheAndShutdown(path);
        }
    }

    @Override
    public void nextPlay() {
        if (mDataSourceList.isEmpty()) {
            return;
        }
        if (currPlayPotion < 0) {
            prepareAsync(0, mDataSourceList.get(0));
        } else {
            if (mDataSourceList.size() > currPlayPotion + 1) {
                prepareAsync(currPlayPotion + 1, mDataSourceList.get(currPlayPotion + 1));
            } else {
                if (mListLooping) {
                    prepareAsync(0, mDataSourceList.get(0));
                }
            }
        }
    }

    @Override
    public void prevPlay() {
        if (mDataSourceList.isEmpty() || currPlayPotion < 0) {
            return;
        }
        if (currPlayPotion == 0) {
            if (mListLooping) {
                prepareAsync(mDataSourceList.size() - 1, mDataSourceList.get(mDataSourceList.size() - 1));
            }
        } else {
            prepareAsync(currPlayPotion - 1, mDataSourceList.get(currPlayPotion - 1));
        }
    }

    @Override
    public boolean isPlaying() {
        if (mMediaPlayer != null) {
            return mMediaPlayer.isPlaying();
        }
        return false;
    }

    @Override
    public AudioPlayEnum getPlayerStatus() {
        return mPlayerStatus;
    }

    @Override
    public void seekTo(long time) {
        try {
            if (mMediaPlayer != null) {
                mMediaPlayer.seekTo(time);
                mSeekTouch = false;
                if (mMediaPlayer.isPlaying()) {
                    synchronized (mProgressLock) {
                        mProgressLock.notifyAll();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void seekStart() {
        mSeekTouch = true;
    }

    @Override
    public void release() {
        mTelephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_NONE);
        mBufferHandler.removeCallbacksAndMessages(null);
        if (mCacheServer != null) {
            AudioCacheManager.getInstance(appContext).unregisterCacheListener();
            mCacheServer.shutdown();
        }
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mAudioStateAlive = false;
            currPlayPotion = -1;
            mMediaPlayer.release();
        }
    }

    @Override
    public long getCurrentPosition() {
        return mMediaPlayer.getCurrentPosition();
    }

    @Override
    public long getDuration() {
        return mMediaPlayer.getDuration();
    }

    @Override
    public int getBufferedPercentage() {
        return mBufferedPercent;
    }

    @Override
    public void setListLooping(boolean isLooping) {
        mListLooping = isLooping;
    }

    @Override
    public void setSingleLooping(boolean isLooping) {
        mSingleLooping = isLooping;
    }

    /**
     * 销毁Tmmer
     */
    private void destroyTimer() {
        if (mProgressTimer != null) {
            mProgressTimer.cancel();
            mProgressTimer = null;
        }
    }

    /**
     * 错误时,自动播放下一首
     */
    private void onErrorPlay() {
        sendPlayerStatus(AudioPlayEnum.PLAYER_ERROR);
        destroyTimer();
        if (mErrorPlayNum < MAX_CONTINUE_ERROR_NUM) {
            mErrorPlayNum++;
            if (mSingleLooping) {
                //单曲循环
                prepareAsync(currPlayPotion, mDataSourceList.get(currPlayPotion));
            } else if (mListLooping || mDataSourceList.size() < currPlayPotion + 1) {
                //列表循环
                nextPlay();
            }
        }
    }

    /**
     * 延时发送是否在缓冲的状态,防止假缓冲
     */
    private void sendBufferingHandler(boolean sendNow, final boolean isBuffering) {
        if (mAudioPlayerEvent != null) {
            mAudioPlayerEvent.onBuffering(isBuffering);
        }
        /*mBufferHandler.removeCallbacksAndMessages(null);
        mBufferHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (mAudioPlayerEvent != null) {
                    mAudioPlayerEvent.onBuffering(isBuffering);
                }
            }
        }, sendNow ? 0 : (long) (2.5 * TIMER_PROGRESS_INTERVAL));*/
    }

    /**
     * 设置当前播放状态
     */
    private void sendPlayerStatus(AudioPlayEnum mStatus){
        mPlayerStatus = mStatus;
        if(mAudioPlayerEvent != null){
            mAudioPlayerEvent.onStatusChange(mPlayerStatus,currPlayPotion);
        }
    }

    /**
     * 定时器检测播放进度
     */
    private void playProgressListener() {
        if (mProgressTimer == null) {
            mProgressTimer = new Timer();
        }
        if (mProgressTask != null) {
            mProgressTask.cancel();
            mProgressTask = null;
        }
        mProgressTask = new TimerTask() {
            @Override
            public void run() {
                while (mAudioStateAlive) {
                    if (mMediaPlayer == null
                            || !mMediaPlayer.isPlaying()
                            || mSeekTouch) {
                        synchronized (mProgressLock) {
                            try {
                                mProgressLock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    } else {
                        try {
                            Thread.sleep(TIMER_PROGRESS_INTERVAL);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if (mAudioPlayerEvent != null
                            && !mSeekTouch
                            && mMediaPlayer.isPlaying()
                            && mMediaPlayer != null) {
                        long currPosition = mMediaPlayer.getCurrentPosition();
                        //播放之前的缓冲在onPrepare时已经缓冲完了,所以这里要排除进度为0
                        if (currPosition != 0 && prevPlayPosition >= currPosition) {
                            sendBufferingHandler(false, true);
                        } else {
                            sendBufferingHandler(true, false);
                        }
                        prevPlayPosition = currPosition;
                        mAudioPlayerEvent.onPlayProgress(mMediaPlayer.getDuration(), currPosition);
                    }
                }
            }
        };
        mProgressTimer.schedule(mProgressTask, 0);
    }

    private IMediaPlayer.OnErrorListener onErrorListener = new IMediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(IMediaPlayer iMediaPlayer, int frameworkErr, int implErr) {
            sendBufferingHandler(true, false);
            onErrorPlay();
            LogUtils.e(frameworkErr + "==>chenpin error" + implErr);
            return true;
        }
    };
    private IMediaPlayer.OnInfoListener onInfoListener = new IMediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(IMediaPlayer iMediaPlayer, int what, int extra) {
            return true;
        }
    };

    private IMediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() {
        @Override
        public void onBufferingUpdate(IMediaPlayer iMediaPlayer, int percent) {
        }
    };

    private IMediaPlayer.OnPreparedListener onPreparedListener = new IMediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(IMediaPlayer iMediaPlayer) {
            if (mAudioPlayerEvent != null) {
                synchronized (mProgressLock) {
                    mProgressLock.notifyAll();
                }
                mErrorPlayNum = 0;
                //准备完毕后发送一次缓存(有可能已经缓存完毕)
                mAudioPlayerEvent.onBufferingUpdate(mBufferedPercent);
                //当前正播放,播放器已经预缓存完毕,开始播放了
                sendBufferingHandler(true, false);
                //记录并发送当前播放状态
                sendPlayerStatus(AudioPlayEnum.PLAYER_PLAYING);
                //开始监听播放进度
                playProgressListener();
            }
        }
    };
    private IMediaPlayer.OnCompletionListener onCompletionListener = new IMediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(IMediaPlayer iMediaPlayer) {
            //播放完毕
            if (mAudioPlayerEvent != null) {
                prevPlayPosition = 0;
                sendPlayerStatus(AudioPlayEnum.PLAYER_COMPLETE);
                destroyTimer();
                if (mSingleLooping) {
                    //单曲循环
                    prepareAsync(currPlayPotion, mDataSourceList.get(currPlayPotion));
                } else if (mListLooping || mDataSourceList.size() < currPlayPotion + 1) {
                    //列表循环
                    nextPlay();
                }

            }
        }
    };
}

 实现代码:

//该处按钮监听
if (v == nextIcon) {
    //下一首
    myAudioManager.nextPlay();
} else if (v == playStatusIcon) {
    //播放状态图标
    if (myAudioManager.isPlaying()) {
        myAudioManager.pause();
    } else if (myAudioManager.getPlayerStatus() == AudioPlayEnum.PLAYER_PAUSE) {
        myAudioManager.reStart();
    } else {
        List<String> list = new ArrayList<>();
        list.add(TEST_MP3_URL);
        list.add(TEST_MP3_URL);
        list.add(TEST_MP3_URL);
        myAudioManager.start(list);
    }
} else if (v == listLoopTxt || v == listLoopTxtWhenScroll) {
    //循环
    myAudioManager.setListLooping(true);
}

 

 

//如何使用回调(这里用seekbar来接收进度)

myAudioManager.setAudioPlayerListener(new AudioPlayerEvent() {

            @Override
            public void onBufferingUpdate(final int percent) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        int max = (int) (myAudioManager.getDuration());
                        if (max > 0) {
                            seekBar.setMax(max);
                            seekBar.setSecondaryProgress(max * percent / 100);
                        }
                    }
                });
            }

            @Override
            public void onBuffering(final boolean isBuffering) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
//                        title.setText(isBuffering ? "正在缓冲..." : "缓冲完毕");
                    }
                });
            }

            @Override
            public void onPlayProgress(final long duration, final long currPosition) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        seekBar.setMax((int) duration);
                        seekBar.setProgress((int) currPosition);
                    }
                });
            }

            @Override
            public void onStatusChange(AudioPlayEnum mStatus, int currPlayPotion) {
                //状态改变,会在这回调,可以更新上层播放UI等
            }
        });

}

//seekbar监听,(注意一定要在开始触摸的时候调用seekStart方法,否则会导致进度条回退)

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        myAudioManager.seekStart();
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        int progress = seekBar.getProgress();
        myAudioManager.seekTo(progress);
    }
});

 

 

在ondestory中销毁

@Override
protected void onDestroy() {
    super.onDestroy();
    if (myAudioManager != null) {
        myAudioManager.release();
    }
}

这个功能集成在项目里,没有单独弄出来上传资源了

 

 类似资料: