音频播放会出现很多情况,比如当我点击的是同一个音频按钮的时候,肯定就是控制音频的播放与暂停,显示时长的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()方法。
记录一下,希望可以帮到一些人,更希望大神给予指点。