本文链接: Android MediaPlayer 基础简介

简单介绍MediaPlayer的基本概念,状态,常用的方法与监听器。

什么是MediaPlayer

MediaPlayer类可以用来播放音视频文件,或者是音频流。开发者可以用它来播放本地音频,或者是网络在线音频。

MediaPlayer属于android.media包。

MediaPlayer的状态

播放控制由状态机控制。在日常生活中,我们常见的音频状态有播放中,暂停,停止,缓冲等等。

MediaPlayer的状态有如下几种:

  • Idle
  • End
  • Error
  • Initialized
  • Preparing
  • Prepared
  • Started
  • Stopped
  • Paused
  • PlaybackCompleted

状态的切换参考官方图例。

这里稍微解释一下状态转换图片。椭圆代表MediaPlayer可能停留的状态。椭圆之间的箭头表示方法调用,状态切换的方向。单箭头表示方法同步调用,双箭头表示异步调用。

从图中我们可以看出状态切换的路径和涉及到的方法。

Idle与End状态

当new一个MediaPlayer或者调用了reset方法,当前MediaPlayer会处于Idle状态。调用release后,会处于End状态。在这2个状态之间的状态可以看做是MediaPlayer对象的生命周期。

在新创建MediaPlayer和调用reset的MediaPlayer之间有一些细微的差别。

这两种情况都处于Idle状态,调用 getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioAttributes(android.media.AudioAttributes), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(long, int), prepare() 或 prepareAsync()方法都会抛出错误,如果是新实例化的MediaPlayer,不会回调 OnErrorListener.onError();但如果是reset后的MediaPlayer,会回调 OnErrorListener.onError()并且转换到Error状态。

如果MediaPlayer对象不再使用了,立即调用release()方法,释放内部播放器占用的资源。这些资源可能是唯一的,比如硬件加速组件。如果调用release失败,可能会引起一连串的MediaPlayer实例失效。当MediaPlayer处于End状态,它就不能再转移到其它状态了。

new一个MediaPlayer,处于Idle状态。如果用create方法创建实例,当创建完成时处于Prepared状态。

发生错误

一些情形可能会让MediaPlayer操作失败,比如不支持的音视频格式,分辨率过高,网络超时等等。

因此在这些情形下错误处理和恢复非常重要。有时候编程错误也会导致MediaPlayer操作错误。

开发者可以设置错误监听器setOnErrorListener(android.media.MediaPlayer.OnErrorListener)。当错误发生时,会调用用户实现的OnErrorListener.onError()方法。

不管有没有设置监听器,错误发生时MediaPlayer会进入Error状态。

为了重复使用同一个MediaPlayer对象,可以使用reset()方法把它从Error状态恢复到Idle状态。

设置错误监听器OnErrorListener是一个好的编程习惯。开发者可以监听到播放引擎的错误通知。

有时候会抛出IllegalStateException异常,比如在错误的状态调用了prepare(), prepareAsync()方法,或是setDataSource方法。

设置音源 setDataSource

调用setDataSource(java.io.FileDescriptor), 或者 setDataSource(java.lang.String), 或者 setDataSource(android.content.Context, android.net.Uri), 或者 setDataSource(java.io.FileDescriptor, long, long), 或者 setDataSource(android.media.MediaDataSource) 可以将MediaPlayer的状态从Idle转到Initialized状态。

如果在Idle状态之外的状态调用了setDataSource(),会抛出IllegalStateException异常。

开发者应该留意setDataSource方法抛出的IllegalArgumentException和IOException异常。

播放音频前必须在Prepared状态

MediaPlayer在开始播放音频前必须处于Prepared状态。

MediaPlayer有同步和异步2种方式来进入Prepared状态。如果是异步的方式,会先转到Preparing状态,再转到Prepared状态。

当准备完成时,内部的播放引擎会回调用户之前设置的OnPreparedListener的onPrepared()方法。

开发者必须注意的是,Preparing状态是一个过渡状态(transient state)。

处于Prepared状态时,可以通过相对应的方法设置音量,屏幕常亮,播放循环等。

开始播放

播放音频必须调用start()方法。调用start()返回成功后,MediaPlayer处于Started状态。

可以通过isPlaying()来判断当前是否在Started状态。

如果开发者设置了OnBufferingUpdateListener,Android内部播放器会向外传递buffer信息。

如果当前处于Started状态,再调用start()方法没有效果。

暂停播放与继续播放

音频可以被暂停播放和继续播放,也可以调整播放的位置。通过pause()方法来暂停音频播放。

成功调用pause()方法后,MediaPlayer进入Paused状态。

应当注意的是,MediaPlayer在Started状态与Paused状态之间切换是异步的。播放音频流的时候,这个转换过程可能会需要几秒钟。

MediaPlayer暂停时,start()方法可以从暂停的位置继续播放。成功调用start方法后会进入Started状态。

处于Paused状态时,调用pause()方法没有效果。

停止

调用stop()方法让MediaPlayer从Started, Paused, Prepared 或 PlaybackCompleted 状态进入 Stopped 状态。

在Stopped状态时,必须先调用prepare() 或 prepareAsync()进入Prepared状态后,才能播放音频。

处于Stopped状态时,调用stop()方法没有效果。

调整播放位置

调用seekTo(long, int)来调整播放位置。

seekTo(long, int)是一个异步方法,虽然它能立刻返回,但实际的位置调整可能会消耗一段时间,特别是在播放音频流的时候。当实际播放位置调整后,内部播放器会回调开发者设置的OnSeekComplete.onSeekComplete()。

在Prepared, Paused 和 PlaybackCompleted状态中,都可以调用seekTo方法。

可以通过getCurrentPosition()方法来获取当前播放位置。开发者可以得知当前播放的进度等等。

播放完毕

音频播放完成后,播放完毕。

如果调用setLooping(boolean)为true,MediaPlayer会停留在Started状态。

如果setLooping为false,内部播放器会调用开发者设置的OnCompletion.onCompletion(),并且进入PlaybackCompleted状态。

处于PlaybackCompleted状态时,调用start()方法可以从头开始播放音频。

常用监听器

开发者可以设置一些监听器,监听MediaPlayer的状态,错误事件等等。开发者应在同一个线程中创建MediaPlayer与设置的监听器。

setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener)

监听MediaPlayer准备完成。一般与prepareAsync配合使用。

setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener)

获知video大小或video大小改变时的监听。

setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener)

监听调整位置完成。

setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener)

播放完成。

mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
// 当前播放完毕
}
});

setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener)

监听缓冲进度。在播放网络音频时常用。

缓冲监听器OnBufferingUpdateListener

    mMediaPlayer.prepareAsync();
mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
// 例如在这里更新UI
}
});

setOnInfoListener(android.media.MediaPlayer.OnInfoListener)

监听普通信息或者警告信息。

setOnErrorListener(android.media.MediaPlayer.OnErrorListener)

监听错误信息。错误发生时,可以在这里处理错误。

mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
LogUtil.e(TAG_PREFIX + " onERR i = " + i + " i1 = " + i1);
return true; // 返回true表示在此处理错误,不会回调onCompletion
}
});

注意onError的返回值。可以选择自己处理error。

         * @return True if the method handled the error, false if it didn't.
* Returning false, or not having an OnErrorListener at all, will
* cause the OnCompletionListener to be called.
*/
boolean onError(MediaPlayer mp, int what, int extra);

需要的权限

播放网络音频时需要Manifest.permission.INTERNET权限。

Android MediaPlayer 基础简介的更多相关文章

  1. Android MediaPlayer 播放音频

    本文链接: Android MediaPlayer 播放音频 主要介绍使用MediaPlayer播放音频的方式.关于MediaPlayer的基础知识,比如状态,可以参考Android MediaPla ...

  2. 005 01 Android 零基础入门 01 Java基础语法 01 Java初识 05 Eclipse简介

    005 01 Android 零基础入门 01 Java基础语法 01 Java初识 05 Eclipse简介 Eclipse是一款集成开发工具--IDE. 集成开发环境(IDE,Integrated ...

  3. 002 01 Android 零基础入门 01 Java基础语法 01 Java初识 02 Java简介

    002 01 Android 零基础入门 01 Java基础语法 01 Java初识 02 Java简介 学习Java的基础语法 Java是一门编程语言,学习的逻辑其实和现实世界的语言是一样的,需要了 ...

  4. 第一部分 Android MediaPlayer 概述

    [IT168 技术文档]本文主要介绍的是Android中很重要也最为复杂的媒体播放器(MediaPlayer)部分的架构.对于Android这样一个完整又相对复杂的系统,一个MediaPlayer功能 ...

  5. Android BLE与终端通信(二)——Android Bluetooth基础科普以及搜索蓝牙设备显示列表

    Android BLE与终端通信(二)--Android Bluetooth基础搜索蓝牙设备显示列表 摘要 第一篇算是个热身,这一片开始来写些硬菜了,这篇就是实际和蓝牙打交道了,所以要用到真机调试哟, ...

  6. Android零基础入门第19节:Button使用详解

    原文:Android零基础入门第19节:Button使用详解 Button(按钮)是Android开发中使用非常频繁的组件,主要是在UI界面上生成一个按钮,该按钮可以供用户单击,当用户单击按钮时,按钮 ...

  7. Android零基础入门第18节:EditText的属性和使用方法

    原文:Android零基础入门第18节:EditText的属性和使用方法 EditText与TextView非常相似,它甚至与TextView 共用了绝大部分XML属性和方法.EditText与Tex ...

  8. Android零基础入门第1节:Android的前世今生

    原文:Android零基础入门第1节:Android的前世今生 现在网上有很多各色Android资料了,但相对来说还是比较零散,Android覆盖的范围极广,最近刚好有机会全部拉通整理一遍,也保存起来 ...

  9. Android零基础入门第82节:Activity数据回传

    上一节学习了将简单的数据从MainActivity传递到SecondActivity,本节一起来学习数据如何从SecondActivity回传到MainActivity. 一.简介 前面己经提到,Ac ...

随机推荐

  1. 洛谷 P4124 [CQOI2016]手机号码

    题意简述 求l~r之间不含前导零,至少有三个相邻的相同数字,不同时含有4和8的11位正整数的个数 题解思路 数位DP,注意在l,r位数不够时补至11位 代码 #include <cstdio&g ...

  2. 弃用 wget, 拥抱多线程下载 axel

    0x00 事件 对于在 Linux 的下载工具而言,比较常用的就是 wget 或者 curl,吾也一直用 wget 的方式进行网络上的资源下载.偶然发现了 axel 这个支持多线程的下载工具,试用了几 ...

  3. UI 组件 | Toggle

    Toggle(复选框)组件 Toggle 是一个 CheckBox,当它和 ToggleGroup 一起使用的时候,可以变成 RadioButton. 创建 Toggle 组件 层级管理器右击-> ...

  4. 线程学习oneday

    进程:执行中的程序叫做进程(Process),是一个动态的概念. 线程:一个进程可以产生多个线程.同多个进程可以共享操作系统的某些资源一样,同一进程的多个线程也可以共享此进程的某些资源(比如:代码.数 ...

  5. 《MyCat分库分表策略详解》

    在我们的项目发展到一定阶段之后,随着数据量的增大,分库分表就变成了一件非常自然的事情.常见的分库分表方式有两种:客户端模式和服务器模式,这两种的典型代表有sharding-jdbc和MyCat.所谓的 ...

  6. Liunx学习总结(二)--目录和文件管理

    之前我们了解了什么是 liunx ,并且认识了它的目录结构,今天我们就来学习下如何进行目录和文件的管理. 创建目录 语法: mkdir [-mp] 目录名称 选项与参数 -m :配置文件的权限喔!直接 ...

  7. 10_switch语句的使用

    /* switch 语句和c语言的用法不同 1.go语句是默认添加break语句的,但c不是默认的 2.go语句添加一个fallthrough语句,可以顺序执行接下来的结构 3.switch在关键词后 ...

  8. Docker Machine的使用

    前面两篇文章(<Asp.Net Core 发布到 Docker(Linux Centos 虚拟机,使用Dockerfile)> <Docker Compose的使用>),简单介 ...

  9. 线程、进程的区别,Java的几个线程状态

    线程.进程的区别        进程的定义:进程就是程序在一个数据集合上的一次执行过程.他与程序的区别在于程序是静态的代码,而进程是动态的执行过程. 进程的特性:1.结构性,进程由程序块.数据块.进程 ...

  10. 牛客小白月赛6 I 公交线路 最短路 模板题

    链接:https://www.nowcoder.com/acm/contest/136/I来源:牛客网 题目描述 P市有n个公交站,之间连接着m条道路.P市计划新开设一条公交线路,该线路从城市的东站( ...