zoukankan      html  css  js  c++  java
  • 【android-音视频】listview中播放音频,实现音频时长的倒计时,暂停,切换。

    音频播放会出现很多情况,比如当我点击的是同一个音频按钮的时候,肯定就是控制音频的播放与暂停,显示时长的textview的暂停与继续。

    当点击的音频按钮不是同一个的时候,

    首先要重置上个点击的音频按钮相对应的音频时长的textview显示。

    比如,第一次点击的是《萍聚》这首歌,时长4:01,应该立即播放此歌曲,并且时长进行倒计时4:01,4:00,3:59.....这样。

    当第二次点击这首歌时,则需要暂停歌曲的播放,并暂停倒计时。

    当在暂停状态点击其他的音频播放按钮的时候,

    重置上次点击的音频,并重置与此对应的时间。根据前后两次点击的音频的url,判断是否需要重新获得mediaplayer实例。

    比如,第一次点击的是《萍聚》,已经播放到2:21。第二次点击的是《五环之歌》,则需要把第一个的Mediaplayer释放掉,再重新得到一个五环之歌的mediaplayer。

    并重置与《萍聚》相对应的textview的时长为4:01(即初始时长).

    当activity切换的时候,转入后台不可见的时候,要释放掉mediaplayer。

    下面请看代码。(时间比较紧,没有整理代码。肯定还有更好的解决办法。还请高手指正!)

      1.MediaPlayerUtils.java

    import java.io.File;
    
    import android.app.ProgressDialog;
    import android.content.Context;
    import android.media.MediaPlayer;
    import android.media.MediaPlayer.OnCompletionListener;
    import android.media.MediaPlayer.OnPreparedListener;
    import android.net.Uri;
    import android.os.Handler;
    import android.os.Message;
    import android.telephony.PhoneStateListener;
    import android.telephony.TelephonyManager;
    import android.widget.SeekBar;
    import android.widget.TextView;
    
    import com.ab.download.AbDownloadThread;
    import com.ab.download.AbFileDownloader;
    import com.ab.download.DownFile;
    import com.ab.download.DownFileDao;
    import com.ab.http.AbFileHttpResponseListener;
    import com.ab.task.AbTaskItem;
    import com.ab.task.AbTaskListener;
    import com.ab.task.AbThread;
    import com.ab.util.AbFileUtil;
    /**
     * 2014-3-24下午4:19:16
     * 
     * @author:hlloworld.Mr-zz
     * 
     * @todo:MediaPlayer工具类,可以得到一个装载好的MediaPlayer,并且装载完毕后会自动播放一次 
     *                                                           1.首先会检查本地是否有指定路径(该路径有项目根目录
     *                                                           +voice+网络路径的文件名组成)
     *                                                           的音频文件 2.如果存在,直接装载播放
     *                                                           3.如果不存在,则异步播放网络音频
     */
    public class MediaPlayerUtils {
    
        private ProgressDialog pd;
        private MediaPlayer player = null;
        private Handler handler = null;
        private static Context context;
        private static MediaPlayerUtils instance = null;
        private UpdateSeekBarThread updateSeekBarThread;
        private int playPosition;
        private DownFile d;//断点续传的文件
        private AbFileDownloader loader;
    
        private MediaPlayerUtils() {
        }
    
        public static MediaPlayerUtils getInstance(Context context) {
            if (instance == null) {
                MediaPlayerUtils.context = context;
                instance = new MediaPlayerUtils();
                TelephonyManager telephonyManager = (TelephonyManager) context
                        .getSystemService(Context.TELEPHONY_SERVICE);
                telephonyManager.listen(new MyPhoneListener(),
                        PhoneStateListener.LISTEN_CALL_STATE);
            }
            return instance;
        }
    
        public void initCountDownPlayer(final String voiceUrl,final Handler handler, final String time,final TextView tv) {
            // 如果sd卡能用,播放sd卡上的文件
            final File voice = new File(XingyunApplication.voiceDir
                    + FileUtil.getFileNameFromUrl(voiceUrl));
            if (CommonUtils.isSDCardExits()) {
                
                if (!voice.exists()) {
                    // 播放网络文件
                    playNetVoiceWithCountDown(voiceUrl, time,tv);
                    // 如果sd卡中没有,先下载
                    downUrl(voiceUrl, voice);
    //                downUrl1(voiceUrl, voice, context);
                } else {
                    try {
                        player = player == null ? new MediaPlayer() : player;
                        player.setOnCompletionListener(new OnCompletionListener() {
                            
                            @Override
                            public void onCompletion(MediaPlayer mp) {
                                // TODO Auto-generated method stub
                                UpdateVoiceTimeThread.getInstance( time,tv).stop();
                            }
                        });
                        player.setDataSource(voice.toString());
                        player.prepare();
                        player.start();
                        UpdateVoiceTimeThread.getInstance( time,tv).start();
                        Message msg = handler.obtainMessage();
                        msg.obj = player;
                        msg.what = Gloable.VOICE_DOWN_OK;
                        handler.sendMessage(msg);
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                
            } else {
                playNetVoiceWithCountDown(voiceUrl, time,tv);
            }
        }
        
        private void playNetVoiceWithCountDown(final String voiceUrl,final String time,final TextView tv){
            // 如果sd卡不能用,直接播放網絡文件
                        showProgress();
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                // TODO Auto-generated method stub
                                Uri uri = Uri.parse(voiceUrl);
                                player = player == null ? MediaPlayer.create(context, uri)
                                        : player;
                                player.setOnCompletionListener(new OnCompletionListener() {
                                    
                                    @Override
                                    public void onCompletion(MediaPlayer mp) {
                                        // TODO Auto-generated method stub
                                        UpdateVoiceTimeThread.getInstance( time,tv).stop();
                                    }
                                });
                                player.setOnPreparedListener(new OnPreparedListener() {
    
                                    @Override
                                    public void onPrepared(MediaPlayer mp) {
                                        // TODO Auto-generated method stub
                                        dissmissProgress();
                                        player.start();
                                        
                                        UpdateVoiceTimeThread.getInstance( time,tv).start();
                                        Message msg = handler.obtainMessage();
                                        msg.obj = player;
                                        msg.what = Gloable.VOICE_DOWN_OK;
                                        handler.sendMessage(msg);
                                    }
                                });
                            }
                        }).start();
    
        }
        
      /**
         * 显示无边框透明的progressdialog
         */
        private void showProgress() {
            pd = new CustomProgressDialog(context);
            pd.setCanceledOnTouchOutside(false);
            pd.show();
        }
    
        /**
         * 隐藏无边框透明的progressdialog
         */
        private void dissmissProgress() {
            if (pd == null) {
                return;
            }
            pd.dismiss();
        }
    
        public void releasePlayer() {
            if (player != null) {
                if (player.isPlaying()) {
                    player.stop();
                }
                player.release();
                player = null;
            }
            if (pd != null) {
                pd.dismiss();
                pd = null;
            }
            context = null;
            instance = null;
            if (updateSeekBarThread != null) {
                handler.removeCallbacks(updateSeekBarThread);
            }
        }
    
        /**
         * 只有电话来了之后才暂停音乐的播放
         */
        static class MyPhoneListener extends android.telephony.PhoneStateListener {
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                switch (state) {
                case TelephonyManager.CALL_STATE_RINGING:// 电话来了
                    if (instance!=null) {
                        instance.callIsComing();
                    }
                    break;
                case TelephonyManager.CALL_STATE_IDLE: // 通话结束
                    if (instance!=null) {
                        instance.callIsDown();
                    }
                    break;
                }
            }
        }
    
        /**
         * 来电话了
         */
        public void callIsComing() {
            if (player.isPlaying()) {
                playPosition = player.getCurrentPosition();// 获得当前播放位置
                player.stop();
            }
        }
    
        /**
         * 通话结束
         */
        public void callIsDown() {
            if (playPosition > 0) {
                player.seekTo(playPosition);
                playPosition = 0;
            }
        }
        
        
        
        
        
        
        
        
        
       
        }
    
    }

    控制textview倒计时的countdownTimer

    import java.text.SimpleDateFormat;
    import android.media.MediaPlayer;
    import android.os.CountDownTimer;
    import android.os.Handler;
    import android.os.Message;
    import android.sax.StartElementListener;
    import android.widget.SeekBar;
    import android.widget.TextView;
    
    /**
     * 2014-3-26下午12:28:44
     * 
     * @author:crazyhelloworld.Mr-zz
     * @todo:
     */
    public class UpdateVoiceTimeThread {
    
        private static CountDownTimer cdt;
        private final static int TIME_CHANGE_DELAY = 1000;
        private final static SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
        private static String time;
        private static TextView tvv;
        private static UpdateVoiceTimeThread instance = null;
        public static long l;
        public static UpdateVoiceTimeThread getInstance( final String stime,final TextView tv){
            if (instance==null) {
                synchronized (UpdateVoiceTimeThread.class) {
                    if (instance == null) {
                        instance = new UpdateVoiceTimeThread();
                        time = stime;
                        tvv = tv;
                        String smin = stime.substring(0, stime.indexOf(":"));
                        String ssec = stime.substring(stime.indexOf(":") + 1, stime.length());
                        int min = Integer.parseInt(smin);
                        int sec = Integer.parseInt(ssec);
                        l = (min * 60 + sec) * 1000;
                        getTimer();
    //                    cdt.start();
                    }
                }
            }
            return instance;
        }
        
        private UpdateVoiceTimeThread(){};
        
        private static CountDownTimer getTimer(){
            if (cdt!=null) {
                cdt.cancel();
                cdt = null;
            }
            cdt = new CountDownTimer(l, TIME_CHANGE_DELAY) {
    
                @Override
                public void onTick(long millisUntilFinished) {
                    // TODO Auto-generated method stub
                    tvv.setText(sdf.format(millisUntilFinished));
                    l = l - TIME_CHANGE_DELAY;
                }
    
                @Override
                public void onFinish() {
      
                    tvv.setText(time);
    
                }
                
            };
            return cdt;
        }
        
        public void start() {
            getTimer();
            cdt.start();
        }
        public void pause(){
            cdt.cancel();
            tvv.setText(sdf.format(l));
        }
        public void stop(){
            instance = null;
            if (cdt!=null) {
                cdt.cancel();
                cdt = null;
            }
            tvv.setText(time);
        }
    
    }

    adapter中声明的判断属性及handler

        /**
         * 根据前后两次点击的地址判断是否需要重新加载mediaplayer的标识
         */
        private static int flag = 0;
        /**
         * 音频播放的实例
         */
        public static MediaPlayer player = null;
        /**
         * 为了比对前后两次点击请求的音频地址是否相同。与issame结合使用,
         * 如果issame=true,则点击的是同一个按钮。直接播放或者暂停
         * 如果issame=false,再判断当前点击的与按钮的音频地址与tempvoiceurl是否一致
         * 如果一致,stop上一个的播放,恢复tvlength的值为初始值。
         * 如果不一致,直接播放
         */
        private String tempVoiceUrl = "";
        /**
         * 当前点击的iv后面的时间textview
         */
        private static TextView tv;
        /**
         * 当前点击的音频的长度
         */
        private static String time;
        /**
         * 当前点击的容器(ImageView)
         */
        private View tempView;
        /**
         * 上个音频的时长
         */
        private String tempTime;
        /**
         * 上个音频时长的容器
         */
        private TextView tempTv;
        /**
         * 前后两次点击的是否是一个imageview的标识
         */
        private boolean isSame = false;
    
        private Handler handler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                switch (msg.what) {
                case Gloable.VOICE_DOWN_OK:
                    player = (MediaPlayer) msg.obj;
                    break;
    
                default:
                    break;
                }
    
            };
        };

    adapter中音频的点击事件

    holder.voice.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    if (!tempVoiceUrl.equals(p.getVoiceUrl())) {
                        MediaPlayerUtils.getInstance(context).releasePlayer();
                        flag = 0;
                    }
                    tv = (TextView) ((LinearLayout) v.getParent()).getChildAt(2);
                    if (v == tempView) {
                        isSame = true;
                    } else {
                        tempView = v;
                        isSame = false;
                    }
    
                    UpdateVoiceTimeThread.getInstance(p.getVoiceTime(), tv).stop();
                    time = p.getVoiceTime();
                    playVoice(p.getVoiceUrl(), time);
                }
            });

    adapter中按钮的点击事件调用的播放方法

    private void playVoice(String url, String time) {
            if (flag == 0) {
                if (NetUtils.isNetworkAvailable(context)) {
                    MediaPlayerUtils.getInstance(context).initCountDownPlayer(url,
                            handler, time, tv);
                    tempVoiceUrl = url;
                    flag = -1;
                } else {
                    Toast.makeText(context,
                            context.getString(R.string.network_not_avaliable), 1)
                            .show();
                }
            } else if (player != null) {
                if (isSame) {
                    if (!player.isPlaying()) {
                        player.start();
                        if (UpdateVoiceTimeThread.l == 0) {
                            UpdateVoiceTimeThread.getInstance(time, tv).start();
                        } else {
                            UpdateVoiceTimeThread
                                    .getInstance(
                                            CommonUtils
                                                    .getStringDate(UpdateVoiceTimeThread.l),
                                            tv).start();
                        }
                    } else {
                        player.pause();
                        UpdateVoiceTimeThread.getInstance(
                                CommonUtils.getStringDate(UpdateVoiceTimeThread.l),
                                tv).pause();
                    }
                    tempTv = tv;
                    tempTime = time;
                } else {
                    player.seekTo(0);
                    player.start();
                    UpdateVoiceTimeThread.getInstance(tempTime, tempTv).stop();
                    UpdateVoiceTimeThread.getInstance(time, tv).start();
    
                }
            }
        }
    
        public static void releasePlayer() {
            MediaPlayerUtils.getInstance(context).releasePlayer();
            if (player != null) {
                player.release();
                player = null;
            }
            flag = 0;
            if (time != null && tv != null) {
                UpdateVoiceTimeThread.getInstance(time, tv).stop();
            }
        }

    adapter中释放player的方法

    public static void releasePlayer() {
            MediaPlayerUtils.getInstance(context).releasePlayer();
            if (player != null) {
                player.release();
                player = null;
            }
            flag = 0;
            if (time != null && tv != null) {
                UpdateVoiceTimeThread.getInstance(time, tv).stop();
            }
        }

    在activity的onPause()回调方法里调用adapter的releasePlayer()方法。

    记录一下,希望可以帮到一些人,更希望大神给予指点。

  • 相关阅读:
    我爱Java系列之---【SpringBoot打成war包部署】
    279. Perfect Squares
    矩阵dfs--走回路
    112. Path Sum
    542. 01 Matrix
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    Invert Binary Tree
    563 Binary Tree Tilt
    145 Binary Tree Postorder Traversal
  • 原文地址:https://www.cnblogs.com/MrZz/p/3663775.html
Copyright © 2011-2022 走看看