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()方法。

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

  • 相关阅读:
    Windows server 2008设置远程桌面
    .NET高级开发工程师 南通红创软件科技有限公司
    silverlight获取浏览器信息交互数据的方法
    silverlight元素FrameworkElement.LayoutUpdated布局变化事件
    Nicholas C. Zakas如何面试前端工程师
    asp.net自动完成控件在用户控件上失效的解决方法
    构建高性能可扩展ASP.NET网站
    关闭sql server 2005远程连接
    使用asp.net实现单点登陆(SSO)功能
    微软首次展示Windows 8:开始界面类似WP7
  • 原文地址:https://www.cnblogs.com/MrZz/p/3663775.html
Copyright © 2011-2022 走看看