播放音频的API
MediaPlayer
MediaPlayer状态图解:
播放本地音乐:
public void play(View v) { String path = et_path.getText().toString(); //1.判空操作,2,判断是否真的存在这个文件,有可能用户输入的是非法的文件路径 try { //1,创建一个多媒体播放器 mediaPlayer = new MediaPlayer(); //2.设置播放资源 mediaPlayer.setDataSource(path); //设置播放错误监听--一般是音频文件损坏了。。 mediaPlayer.setOnErrorListener(new OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { return false; } }); //3.准备一下 mediaPlayer.prepare(); //4. 开始播放 mediaPlayer.start(); //播放完毕的监听,如果已经播放完毕,那么可以播放下一首歌,或者继续播放当前的这首歌 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mediaPlayer.seekTo(0); mediaPlayer.start(); } }); } catch (Exception e) { e.printStackTrace(); } } public void pause(View v) { if(mediaPlayer.isPlaying()){ mediaPlayer.pause(); }else{ mediaPlayer.start(); } } public void stop(View v) { if(mediaPlayer.isPlaying()){ mediaPlayer.stop(); //停止音乐播放 mediaPlayer.release();//释放资源 ---> end } }
播放网络音乐:
public void play(View v) { String path = et_path.getText().toString(); //1.判空操作,2,判断是否真的存在这个文件,有可能用户输入的是非法的文件路径 try { //1,创建一个多媒体播放器 mediaPlayer = new MediaPlayer(); //2.设置播放资源 mediaPlayer.setDataSource(path); //设置播放错误监听--一般是音频文件损坏了。。 /* mediaPlayer.setOnErrorListener(new OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { return false; } });*/ //3.准备一下 ,这是在主线程准备的。 //mediaPlayer.prepare(); //开始异步缓冲,在子线程里面准备 mediaPlayer.prepareAsync(); //注册一个缓冲可以播放的监听器 mediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { dialog.dismiss(); //4. 开始播放 mediaPlayer.start(); //播放完毕的监听,如果已经播放完毕,那么可以播放下一首歌,或者继续播放当前的这首歌 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mediaPlayer.seekTo(0); mediaPlayer.start(); } }); } }); } catch (Exception e) { e.printStackTrace(); } } public void pause(View v) { if(mediaPlayer.isPlaying()){ mediaPlayer.pause(); }else{ mediaPlayer.start(); } } public void stop(View v) { if(mediaPlayer.isPlaying()){ mediaPlayer.stop(); //停止音乐播放 mediaPlayer.release();//释放资源 ---> end } }
SoundPool(声音池)
int id ; SoundPool pool ; public void init() { pool = new SoundPool( 3, //最多能放多少道音频文件 AudioManager.STREAM_MUSIC, // 存储的流类型是什么类型 0); //没有生命影响,给0 //加载音频文件到池子里面。 id = pool.load(this, R.raw.shoot, 1); } /** * @param soundID a soundID returned by the load() function * @param leftVolume left volume value (range = 0.0 to 1.0) * @param rightVolume right volume value (range = 0.0 to 1.0) * @param priority stream priority (0 = lowest priority) * @param loop loop mode (0 = no loop, -1 = loop forever) * @param rate playback rate (1.0 = normal playback, range 0.5 to 2.0) 播放速率 * @return non-zero streamID if successful, zero if failed * / public void shoot(View v){ pool.play(id, 1, 1, 0, 0, 1.0f); }
MediaPlayer较为笨重,播放前都需要做下准备工作(prepare(),prepareAync()),所以不适合短时间内播放大量的音频文件;SoundPool则主要用来短时间内播放大量密集的音频,并且音频的时间比较短(如按键音,射击游戏的枪声)
播放视频的API
VideoView,MediaController
//1.找到播放视频的控件 VideoView vv = (VideoView) findViewById(R.id.vv); //2.指定播放的视频源 vv.setVideoPath("/mnt/sdcard/oppo.3gp"); MediaController controller = new MediaController(this); controller.setAnchorView(vv); //设置视频的控制器 暂停、播放、快进、快退 vv.setMediaController(controller); //3.开始播放 vv.start();
SurfaceView + MediaPlay播放视频
SurfaceView介绍
a. surfaceView内部使用的是双缓冲机制,可以单位时间内大量的渲染、显示不同的画面
线程0: 显示画面—计算数据 —显示画面
线程1: 计算数据—-显示画面—计算数据
b. surfaceView是一个比较耗费内存的控件,系统不会一开始上来就渲染这个控件,而是等界面能够看到的时候才去渲染这个控件,才去显示它。
c. SurfaceView可见时调
public void surfaceCreated(final SurfaceHolder holder)
;SurfaceView不可见时调public void surfaceDestroyed(SurfaceHolder holder)
;如果在SurfaceView不可见时调holder.lockCanvas()
,则得到的canvas为null。sv = (SurfaceView) findViewById(R.id.sv); //1.得到surfaceView的控制器 SurfaceHolder holder = sv.getHolder(); holder.addCallback(new Callback() { //当surfaceView销毁的时候调用 @Override public void surfaceDestroyed(SurfaceHolder holder) { System.out.println("---surfaceDestroyed--"); } //当surfaceView创建的时候调用 @Override public void surfaceCreated(final SurfaceHolder holder) { //此方法在主线程调用 System.out.println("---surfaceCreated--"+Thread.currentThread().getName()); //获取到surfaceview的控制器 //SurfaceHolder holder = sv.getHolder(); new Thread(){//可以在子线程更新SurfaceView控件 public void run() { int radius = 5; for (int i = 0; i < 10; i++) { //由于界面没显示,所以画布是空的。 Canvas canvas = holder.lockCanvas(); canvas.drawColor(Color.BLACK); Paint paint = new Paint(); paint.setColor(Color.RED); radius +=i; canvas.drawCircle(100, 100, radius, paint); //解锁画布 holder.unlockCanvasAndPost(canvas); SystemClock.sleep(100); } }; }.start(); } //当surfaceView发生改变的时候调用 @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { System.out.println("---surfaceChanged--"); } });
SurfaceView + MediaPlayer播放视频
MediaPlayer只能播放出音频,包括视频文件中的音频;而视频中的画面MediaPlayer通过提供接口
public void setDisplay(SurfaceHolder sh)
交给了SurfaceHolder处理。sp = getSharedPreferences("config", 0); SurfaceView sv = (SurfaceView) findViewById(R.id.sv); sv.getHolder().addCallback(new Callback() { @Override public void surfaceDestroyed(SurfaceHolder holder) { if(mediaPlayer != null){ //获取到当前的播放位置,下次播放时recovery int position = mediaPlayer.getCurrentPosition(); Editor editor = sp.edit(); editor.putInt("position", position); editor.commit(); mediaPlayer.release(); mediaPlayer = null; } } @Override public void surfaceCreated(SurfaceHolder holder) { //应该在这个地方去播放视频了。 try { int position = sp.getInt("position", 0); mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource("/mnt/sdcard/oppo.3gp"); mediaPlayer.prepare(); //指定播放的画面显示到holder里面去,实际上就是显示到surfaceView里面去 mediaPlayer.setDisplay(holder); mediaPlayer.seekTo(position);//跳转到指定位置播放 mediaPlayer.start(); } catch (Exception e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } });
Notice
- 可以在子线程里面更新UI的控件:
- SurfaceView
- ProgressBar 进度条