音頻播放會出現很多情況,比如當我點擊的是同一個音頻按鈕的時候,肯定就是控制音頻的播放與暫停,顯示時長的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()方法。
記錄一下,希望可以幫到一些人,更希望大神給予指點。