【android-音视频】listview中播放音频,实现音频时长的倒计时,暂停,切换。

时间:2021-02-10 22:03:07

音频播放会出现很多情况,比如当我点击的是同一个音频按钮的时候,肯定就是控制音频的播放与暂停,显示时长的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()方法。

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