Android音频的播放
来源:互联网 发布:批量注册淘宝号 编辑:程序博客网 时间:2024/05/20 11:20
一、简介
Android的多媒体框架包括支持播放多种常见的媒体类型,使您可以轻松的把音频、视屏和图像集成到您的应用。您可以播放音频或视屏媒体文件,这些文件是存储在你的应用程序的资源文件中的。应用程序的资源文件可以是文件系统中独立的文件,或者通过网络连接获取的一个数据流,所有使用MediaPlayer APIS的资源文件。
注意:您只能在标准输出设备上播放音频数据。目前,标准输出设备是移动设备的扬声器或耳机。您不能在谈话音频调用期间播放声音文件。
1、基础
下面的类是Android框架中用于播放声音的类:
MediaPlayer:这个类主要用于播放声音和视屏
AudioManager:这个类主要管理音频和音频输出设备
2、声明Manifest文件
//网络权限申明
<uses-permission android:name="android.permission.INTERNET" />
如果您的播放应用需要阻止屏幕变暗或者阻止处理器睡眠,或者使用MediaPlayer.setScreenOnWhielePlaying()或MedidaPlayer.setWakeMode()方法,需要加入下面的权限。
//唤醒锁申明
<uses-permission android:name="android.permission.WAKE_LOCK" />
二、使用MediaPlayer
媒体框架中最重要的组件之一就是MediaPlayer类,此类的对象可以用少量的设置即能获取,解码和播放音频视屏,它支持多种媒体源,比如:
- 本地资源
- 内部URI,比如从您的ContentResolver取得的URI
- 外部URI(媒体流)
1、播放本地资源
//播放本地资源文件,create方法中包括了setDataSource和prepare的执行MediaPlayer _mp = MediaPlayer.create(this, R.raw.millets);_mp.start();
2、播放一个本地URI
//播放文本文件的资源文件 String _path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + "/millets.mp4"; try { //也可以采用这种方式创建对象 MediaPlayer _mpFile = new MediaPlayer(); _mpFile.setDataSource(this, Uri.parse(_path)); _mpFile.prepare();//同步执行 _mpFile.start(); } catch (IOException e) { e.printStackTrace(); }
3、播放网络地址
//播放网络的资源 String _netPath = "http://.mp4"; MediaPlayer _netMp = new MediaPlayer(); try { _netMp.setDataSource(this, Uri.parse(_netPath)); _netMp.prepareAsync();//异步执行 //需要等待prepareAsync准备结束后,回调通知才可以播放 _netMp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); } }); } catch (IOException e) { e.printStackTrace(); }
4、管理状态
MediaPlayer有一个内部的状态,因为特定的操作只能在特定的状态时才能有效。如果你在错误的状态下执行一个操作,系统可能抛出一个异常或者导致一个意外的行为。
5、释放MediaPlayer
MediaPlayer可能要消耗大量的系统资源。因此您应该总是采用一些额外的措施来确保在一个MediaPlayer实例上不会挂起太长的时间。当您用玩MediaPlayer时,您应该总是调用release()来保证任何分配给MeidaPlayer的系统资源被正确的释放。
mediaPlayer.release();mediaPlayer = null;
6、完整例子:
public class MediaMainActivity extends BaseActivity implements View.OnClickListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener { //UI private android.widget.Button buttonpre; private android.widget.Button buttonstart; private android.widget.Button buttonpause; private android.widget.Button buttonnext; private MediaPlayer mMediaPlayer; //data private ArrayList<String> mMusicList; private int mMusicIndex = 0; private boolean isPaused = false; @Override public void initData(Bundle savedInstanceState) { //init music data String _musicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath(); String _a = _musicPath + File.separator + "mbc.mp3"; String _b = _musicPath + File.separator + "rgyzd.mp3"; String _c = _musicPath + File.separator + "rga.mp3"; String _d = _musicPath + File.separator + "zxk.mp3"; String _e = _musicPath + File.separator + "aj.mp3"; mMusicList = new ArrayList<>(); mMusicList.add(_a); mMusicList.add(_b); mMusicList.add(_c); mMusicList.add(_d); mMusicList.add(_e); //init media mMediaPlayer = new MediaPlayer(); mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnErrorListener(this); } @Override public void initView(Bundle savedInstanceState) { setContentView(R.layout.activity_media_main); this.buttonnext = (Button) findViewById(R.id.button_next); this.buttonnext.setOnClickListener(this); this.buttonpause = (Button) findViewById(R.id.button_pause); this.buttonpause.setOnClickListener(this); this.buttonstart = (Button) findViewById(R.id.button_start); this.buttonstart.setOnClickListener(this); this.buttonpre = (Button) findViewById(R.id.button_pre); this.buttonpre.setOnClickListener(this); } @Override public void loadData(Bundle savedInstanceState) { } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button_start: if (isPaused) { mMediaPlayer.start(); isPaused = false; } else { this.startPlayMusic(); } break; case R.id.button_pause: pausePlay(); break; case R.id.button_pre: this.startPre(); break; case R.id.button_next: this.startNext(); break; } } /** * 开始重新播放音乐 */ private void startPlayMusic() { if (mMediaPlayer.isPlaying()) { mMediaPlayer.stop(); } mMediaPlayer.reset(); try { mMediaPlayer.setDataSource(this, Uri.parse(mMusicList.get(mMusicIndex))); mMediaPlayer.prepareAsync(); isPaused = false; } catch (IOException e) { e.printStackTrace(); } } /** * 暂停播放 */ private void pausePlay() { if (mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); isPaused = true; } } /** * 播放上一首 */ private void startPre() { if (mMusicIndex - 1 >= 0) { mMusicIndex--; } else { mMusicIndex = mMusicList.size() - 1; } this.startPlayMusic(); } /** * 播放下一首 */ private void startNext() { if (mMusicIndex + 1 < mMusicList.size()) { mMusicIndex++; } else { mMusicIndex = 0; } this.startPlayMusic(); } @Override public void onCompletion(MediaPlayer mp) { this.startNext(); } @Override public boolean onError(MediaPlayer mp, int what, int extra) { if (null != mMediaPlayer) { mMediaPlayer.reset(); } return true; } @Override public void onPrepared(MediaPlayer mp) { mp.start(); } @Override protected void onDestroy() { super.onDestroy(); if (null != mMediaPlayer) { if (mMediaPlayer.isPlaying()) { mMediaPlayer.stop(); } mMediaPlayer.release(); } }}
三、在服务中使用MediaPlayer
如果您希望您的媒体在您的应用不出现在屏幕上时仍然能够在后台播放,也就是您希望当用户与其他应用交互时仍能继续播放,那么您必须启动一个Service并且通过它来控制MediaPlayer实例。
1、开启服务
public class MyService extends Service implements MediaPlayer.OnPreparedListener { private static final String ACTION_PLAY = "com.example.action.PLAY"; MediaPlayer mMediaPlayer = null; public int onStartCommand(Intent intent, int flags, int startId) { ... if (intent.getAction().equals(ACTION_PLAY)) { mMediaPlayer = ... // initialize it here mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.prepareAsync(); // prepare async to not block main thread } } /** Called when MediaPlayer is ready */ public void onPrepared(MediaPlayer player) { player.start(); }}
2、处理异步的错误:
public class MyService extends Service implements MediaPlayer.OnErrorListener { MediaPlayer mMediaPlayer; public void initMediaPlayer() { // ...initialize the MediaPlayer here... mMediaPlayer.setOnErrorListener(this); } @Override public boolean onError(MediaPlayer mp, int what, int extra) { // ... react appropriately ... // The MediaPlayer has moved to the Error state, must be reset! }}
3、使用唤醒锁
在后台播放媒体的应用时,当您的Service正在运行时,设备可能进入休眠,因为Android系统在休眠时会试着节省电能,那么系统会试着关闭电话的任何不必要的特性,包括CPU和WIFI,然而,如果您的Service正在播放或者接受音乐,您就想阻止系统干涉您的播放工作,为了在上述情况下保证您的service继续运行,您就必须使用”wakelocks”。一个wakelock是一种通知系统在手机空闲时也能为您的应用保留所用特性的途径。
注意:您总是应该保守的使用wekelocks并且尽在真正需要时才持有它,因为它会显著减少设备电池的寿命。
①设置唤醒锁:
当您的MediaPlayer播放时,要保持CPU持续运行,在初始化MediaPlayer时需要调用setWakeMode(),一旦您这样做了,MediaPlayer就会在播放时持有一个特定的锁,并在暂停或停止时释放它:
mMediaPlayer = new MediaPlayer();// ... other initialization here ...mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
4、请求WIFILOCK:
WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)) .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");wifiLock.acquire();
①释放锁
当您暂停或者停止媒体或者当你现在不需要网络时,您应该释放这个锁:
wifiLock.release();
5、使用Notification来在前台显示
String songName;// assign the song name to songNamePendingIntent 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);
6、完整代码:
①Activity
public class MediaPlayServiceActivity extends BaseActivity implements View.OnClickListener { private android.widget.Button servicebuttonstart; private android.widget.Button servicebuttonpause; private android.widget.Button servicebuttonover; @Override public void initData(Bundle savedInstanceState) { } @Override public void initView(Bundle savedInstanceState) { setContentView(R.layout.activity_media_play_service); this.servicebuttonover = (Button) findViewById(R.id.service_button_over); this.servicebuttonover.setOnClickListener(this); this.servicebuttonpause = (Button) findViewById(R.id.service_button_pause); this.servicebuttonpause.setOnClickListener(this); this.servicebuttonstart = (Button) findViewById(R.id.service_button_start); this.servicebuttonstart.setOnClickListener(this); } @Override public void loadData(Bundle savedInstanceState) { } @Override public void onClick(View v) { switch (v.getId()) { //启动播放音乐服务 case R.id.service_button_start: Intent _intentStart = new Intent(this, MediaPlayService.class); _intentStart.setAction(Common.ACTION_START); startService(_intentStart); break; //启动暂停音乐服务 case R.id.service_button_pause: Intent _intentPause = new Intent(this, MediaPlayService.class); _intentPause.setAction(Common.ACTION_PAUSE); startService(_intentPause); break; //启动停止音乐服务 case R.id.service_button_over: Intent _intentOver = new Intent(this, MediaPlayService.class); _intentOver.setAction(Common.ACTION_OVER); startService(_intentOver); break; } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { } return super.onKeyDown(keyCode, event); }}
②Service
public class MediaPlayService extends Service implements MediaPlayer.OnPreparedListener, AudioManager.OnAudioFocusChangeListener { //声明MediaPlayer private MediaPlayer mMP; //声明音乐的地址 private String mMusicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC) + File.separator + "zxk.mp3"; //声明WifiLock private WifiManager.WifiLock mWifiLock; //声明AudioManager private AudioManager mAudioManager; @Override public void onCreate() { super.onCreate(); //获取音频对象 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); int _results = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); if (AUDIOFOCUS_REQUEST_GRANTED == _results) { initMediaPlayer(); } else { } } /** * 初始化MediaPlayer中的一些配置 */ public void initMediaPlayer() { mMP = new MediaPlayer(); mMP.setOnPreparedListener(this); //保证不会被后台清理掉 mMP.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); //保证WIFI不会被休眠 WifiManager _wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); mWifiLock = _wifiManager.createWifiLock("MyLock"); mWifiLock.acquire(); //设置Notification createNotification(); } /** * 创建一个通知,用于在前台显示 */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void createNotification() { Notification.Builder _builder = new Notification.Builder(this); _builder.setTicker("我的第一个音乐播放器"); _builder.setSmallIcon(R.mipmap.ic_launcher); _builder.setContentTitle("我的音乐神器"); _builder.setContentInfo("正在播放"); PendingIntent _pI = PendingIntent.getActivity(this, 0, new Intent(this, MediaPlayServiceActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); _builder.setContentIntent(_pI); NotificationManager _nM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Notification _notification = _builder.build(); _nM.notify(0, _notification); startForeground(0, _notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { String _stringAction = intent.getAction(); switch (_stringAction) { //播放音乐action case Common.ACTION_START: mMP.reset(); try { mMP.setDataSource(getApplicationContext(), Uri.parse(mMusicPath)); mMP.prepareAsync(); } catch (IOException e) { e.printStackTrace(); } break; //暂停音乐action case Common.ACTION_PAUSE: if (mMP.isPlaying()) { mMP.pause(); } break; //结束音乐action case Common.ACTION_OVER: if (mMP.isPlaying()) { mMP.stop(); } mMP.release(); break; case Common.ACTION_STOP: if (mMP.isPlaying()) { mMP.stop(); } break; } return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onPrepared(MediaPlayer mp) { mp.start(); } @Override public void onDestroy() { super.onDestroy(); //释放WifiLock mWifiLock.release(); //停止通知在前台显示 stopForeground(true); //解绑监听 if (null != this.mAudioManager) { this.mAudioManager.abandonAudioFocus(this); } } @Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { //已经获得焦点 case AudioManager.AUDIOFOCUS_GAIN: if (null == mMP) { this.initMediaPlayer(); } else if (!mMP.isPlaying()) { mMP.start(); } mMP.setVolume(1.0f, 1.0f); break; //长期失去焦点 case AudioManager.AUDIOFOCUS_LOSS: if (null != mMP) { if (mMP.isPlaying()) { mMP.stop(); } mMP.release(); mMP = null; } break; //失去焦点,但是很快将会获取 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: if (null != mMP) { if (mMP.isPlaying()) { mMP.pause(); } } break; //失去焦点,允许以小声音播放 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: if (null != mMP) { if (mMP.isPlaying()) { mMP.setVolume(0.1f, 0.1f); } } break; } }}
四、处理音频的焦点
1、要请求音频焦点,您必须从AudioManager调用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.}
注意:requestAudioFocus()的第一个参数是一个AudioManager.OnAudioFocusChangeListener,它的onAudioFocusChange()方法在音频焦点发生改变时调用,因此,您也可以在您的Service和Activity上实现此接口
2、Service实现onAudioFocusChangeListener接口
class MyService extends Service implements AudioManager.OnAudioFocusChangeListener { // .... public void onAudioFocusChange(int focusChange) { // Do something based on focus change... }}
注意:参数focusChange告诉你焦点如何发生了变化
- AUDIOFOCUS_GAIN: You have gained the audio focus.
- AUDIOFOCUS_LOSS: You have lost the audio focus for a presumably long time. You must stop all audio playback. Because you should expect not to have focus back for a long time, this would be a good place to clean up your resources as much as possible. For example, you should release the MediaPlayer.
- AUDIOFOCUS_LOSS_TRANSIENT: You have temporarily lost audio focus, but should receive it back shortly. You must stop all audio playback, but you can keep your resources because you will probably get focus back shortly.
- AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: You have temporarily lost audio focus, but you are allowed to continue to play audio quietly (at a low volume) instead of killing audio completely.
注意:音频焦点API仅在API level8(Android2.2)及更高版本上可以使用
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; }}
3、完整代码见上
五、处理AUDIO_BECOMING_NOISY意图(耳机拔出)
很多良好的音频播放的应用都会在那些导致声音变成噪音(通过外部扬声器输出)的事件发生时自动停止播放。例如,这可能发生在当一个用户用耳机听音乐时突然断开了耳机连接,音频从扬声器播放可能不是用户所期望的。
1、可以通过处理ACTION_AUDIO_BECOMIING_NOISY intent来保证您的应用在此情况下停止播放音乐,您可以把如下代码添加到您的manifest来注册一个receiver。
<receiver android:name=".MusicIntentReceiver"> <intent-filter> <action android:name="android.media.AUDIO_BECOMING_NOISY" /> </intent-filter></receiver>
2、创建一个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)) { // signal your service to stop playback // (via an Intent, for instance) } }}
- Android音频的播放
- Android中音频的播放
- Android中音频的播放
- Android 音频的播放之一
- Android开发之初探音频的播放
- Android播放音频的两种方式
- Android 模拟器播放音频需要的权限
- android MediaPlayer 播放各种来源的音频
- Android 音频的播放之二MediaPlayer
- Android播放音频的两种方式
- Android的音频录制与播放
- Android音频播放器的实现
- Android音频的播放与录制
- android音频播放SoundPool的使用
- android绘制播放音频的波形图
- Android AudioTrack 播放音频
- Android MediaPlayer播放音频
- android:音频播放
- 从零开始学习Android开发-创建第一个App
- 第七届蓝桥杯 方格填数
- OnDraw()和OnPaint()有什么区别?
- 03-JS特效-三大系列之scroll系列
- 海航生态科技舆情大数据平台容器化改造
- Android音频的播放
- Node.js后台数据处理相关方法
- 虚拟机无法联网(Ubuntu 14.04)
- SAP BI
- 小骆驼
- 三个月准备研究生数学建模得二等国奖
- 第十五周项目3—B-树的基本操作
- Java实现冒泡排序和杨辉三角
- CC26XX之OAD(转)