参考:
http://developer.android.com/guide/topics/media/mediaplayer.html
最近接触了项目播放的模块,就来总结下吧.
声明权限
"android.permission.INTERNET" />
唤醒权限(后面会用到)
"android.permission.WAKE_LOCK" />
顺便说下AudioManager.setAudioStream(STREAM_RING,STREAM_RING,STREAM_VOICE_CALL等等)就是设置MediaPlayer对应的流.我们平时按音量键弹出的音量条有时候是铃声,有时候是媒体,说明不同的流对应独立的音量设置.系统会根据当前播放的流弹出对应的音量条.
关于prepare().谷歌推荐做法是调用prepareAsync()然后设置OnPrepareListener在onPrepare()里进行播放.因为解码一些比较大的文件的时候会花一些时间从而导致ANR.其实这个也不一定,灵活运用就好.
一句话,在错误的状态做错误的处理会出错.呵呵…..听起来像废话
先上一张图
setDateSource()–>initialState
prepare() or prepareAsync() –>PrepareState
之后你就可以解锁很多姿势比如start() pause() seekTo()等
调用 stop()之后你就需要重新初始化了,这时候调用start pause等就会报错.
推荐的释放方式:
mediaPlayer.release();
mediaPlayer = null;
尽量在Service中控制Mediaplayer,可以避免很多问题,比如横竖屏的切换.
setOnErrorListener()一般用来写reset Mediaplayer的代码.
当我们手机在后台运行app时,一旦进入sleep状态,就会做一些省电的措施比如关闭wifi,降低CPU运行效率.这样MediaPlayer就不能正常播放.安卓提供了一些方法能保证MediaPlayer正常播放.
唤醒CPU:
MediaPlayer.setWakeMode().调用这个方法,会在播放的时候hold住这个锁,在release或pause时候释放这个锁.
mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
唤醒wifi:
网络播放需要保持wifi开启.
WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
wifiLock.acquire();
相比上一个锁,这个锁是需要手动释放的
wifiLock.release();
也就是做成一个Notification.
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0,
new Intent(getApplicationContext(), MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new Notification();
notification.tickerText = text;
notification.icon = R.drawable.play0;
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notification.setLatestEventInfo(getApplicationContext(), "MusicPlayerSample",
"Playing: " + songName, pi);
startForeground(NOTIFICATION_ID, notification);
//不用了的话就调用
stopForeground(true)
这里的知识点都跟Service,Notification有关了,不打算在这篇里详讲.就好比面向对象编程的其中一个原则——单一职责原则:一个类设计的时候最好只做一件事(Ps:这特么跟写文章有毛的关系,明明就是懒好吗!).
这个功能点是用起来最高大上的.
首先说一下,手机里有很多MediaPlayer播放器,各个app之间是没有代码的交集的.我们在播放音乐的过程中收到短信提示音,播放器会调低音量,收到来电会暂停播放,这些就是通过焦点机制完成的.
请求焦点requestAudioFocus:
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// could not get audio focus.
}
this指的是实现OnAudioFocusChangeListene的类
class MyService extends Service implements AudioManager.OnAudioFocusChangeListener {
public void onAudioFocusChange(int focusChange) {
// Do something based on focus change...
}
}
示例代码:
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
if (mMediaPlayer == null) initMediaPlayer();
else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();
mMediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
就是耳机的插口从洞里面拔出时,如果不做处理那就会让声音从手机扩音器放出来.顾名思义说的就是这种noisy的情况.
这时安卓会发送一个intent,我们需要定义一个广播去接受他.
manifest注册:
<receiver android:name=".MusicIntentReceiver">
<intent-filter>
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
intent-filter>
receiver>
代码处理:
public class MusicIntentReceiver extends android.content.BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
if (intent.getAction().equals( android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
// 暂停就可以了
}
}
}
安卓系统会把音频信息加入数据库(找不到就重启下)方便我们通过Content Provider查找.
ContentResolver contentResolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor == null) {
// query failed, handle error.
} else if (!cursor.moveToFirst()) {
// no media on the device
} else {
int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
do {
long thisId = cursor.getLong(idColumn);
String thisTitle = cursor.getString(titleColumn);
// ...process entry...
} while (cursor.moveToNext());
}
找到数据后进行调用:
long id = /* retrieve it from somewhere */;
Uri contentUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setDataSource(getApplicationContext(), contentUri);
以上是工作中经常用到的东西,安卓已经在APIGuide里帮我们总结了.我只是负责翻译,多看看官网的东西还是比较实用的,有事比去搜索一些博客要全面很多.