Android Media Playback

原文

The Android multimedia framework includes support for playing variety of common media types, so that you can easily integrate audio, video and images into your applications. You can play audio or video from media files stored in your application's resources (raw resources), from standalone files in the filesystem, or from a data stream arriving over a network connection, all using MediaPlayer APIs.

Android多媒体框架包含对多种常见媒体类型的支持,所以你可以容易的在自己的应用中集成音频,视频和图片。你可以播放应用内的资源文件,或文件系统中独立的文件,也可以通过网络数据流来播放,这些功能都使用MediaPlayer APIs实现。

Note: You can play back the audio data only to the standard output device. Currently, that is the mobile device speaker or a Bluetooth headset. You cannot play sound files in the conversation audio during a call.

注意:你只能通过标准输出设备播放音频。当前,这包括移动设备的扬声器或者蓝牙耳机。你不能在用户打电话时播放音频。

The Basics

在Android Framework中,下面两个类用来播放声音和视频:

MediaPlayer  此类是播放声音和视频的主要API。

AudioManager 此类管理音频资源和音频在设备上的输出。

Manifest Declarations

Before starting development on your application using MediaPlayer, make sure your manifest has the appropriate declarations to allow use of related features.

在开始使用MediaPlayer之前,确保你的清单文件中声明了与相关特性有关的权限:

  • Internet Permission - 如果你使用MediaPlayer播放网络内容,应用需要网络访问权限。

  • Wake Lock Permission - 如果你的应用需要保持屏幕不变暗或者处理器不休眠,或者使用MediaPlayer.setScreenOnWhilePlaying()MediaPlayer.setWakeMode()方法,你需要请求以下权限:

Using MediaPlayer

One of the most important components of the media framework is the MediaPlayer class. An object of this class can fetch, decode, and play both audio and video with minimal setup. It supports several different media sources such as:

媒体框架中最重要的组件之一是MediaPlayer类。该类的对象可以用最少的步骤获取,解码和播放音频和视频。它支持多种媒体源,例如:

  • 本地资源

  • 内部URI,例如用于Content Resolver的URI

  • 外部URL(流)

Android支持的媒体类型,见此文档:Android Supported Media Formats

下面的例子显示了如何播放本地raw资源(应用res/raw目录下)

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you

本例中,一个“raw”资源是一个系统不会尝试用特殊方式去解析的文件。然而,此资源的内容不能是原始音频。它应该是根据支持的格式恰当编码和格式化的文件。

下面的例子显示如何通过本地URI播放:

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();

下面的例子显示如何通过HTTP访问URL来播放:

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

注意:如果你通过URL播放在线媒体文件,该文件必须可以渐近下载(Progressive download)。

警告:在使用setDataSource()时,必须捕获或者传递IllegalArgumentException和IOException,因为你引用的文件可能不存在。

Asynchronous Preparation

Using MediaPlayer can be straightforward in principle. However, it's important to keep in mind that a few more things are necessary to integrate it correctly with a typical Android application. For example, the call to prepare() can take a long time to execute, because it might involve fetching and decoding media data. So, as is the case with any method that may take long to execute, you should never call it from your application's UI thread.

原则上,使用MediaPlayer是简单直接的。然而集成在Android应用中时,有几点需要注意。例如,调用prepare()可能会花费很长时间,因为此方法涉及到媒体数据的获取和解码,因此不应该在UI线程调用。

To avoid hanging your UI thread, spawn another thread to prepare the MediaPlayer and notify the main thread when done. However, while you could write the threading logic yourself, this pattern is so common when using MediaPlayer that the framework supplies a convenient way to accomplish this task by using the prepareAsync() method. This method starts preparing the media in the background and returns immediately. When the media is done preparing, the onPrepared() method of the MediaPlayer.OnPreparedListener, configured through setOnPreparedListener() is called.

要避免挂起UI线程,使用另一个线程来准备MediaPlaer,在完成时通知主线程。然而,虽然你可以自己写线程逻辑,此框架提供了prepareAsync方法来简化这一工作。此方法立刻返回,在后台执行准备工作,完成后通过回调通知调用者。

Managing State

Another aspect of a MediaPlayer that you should keep in mind is that it's state-based. That is, the MediaPlayer has an internal state that you must always be aware of when writing your code, because certain operations are only valid when then player is in specific states. If you perform an operation while in the wrong state, the system may throw an exception or cause other undesireable behaviors.

关于MediaPlayer的另一个关注点是它是基于状态的。也就是说,你写代码时必须始终意识到MediaPlayer有内部状态,因为某些操作只在player处于特定状态时才有效。如果你在错误的状态下执行操作,系统可能会抛出异常或者引发其他不需要的行为。

MediaPlayer类文档中展示了MediaPlayer的完整状态图。

Releasing the MediaPlayer

A MediaPlayer can consume valuable system resources. Therefore, you should always take extra precautions to make sure you are not hanging on to a MediaPlayer instance longer than necessary. When you are done with it, you should always call release() to make sure any system resources allocated to it are properly released. For example, if you are using a MediaPlayer and your activity receives a call to onStop(), you must release the MediaPlayer, because it makes little sense to hold on to it while your activity is not interacting with the user (unless you are playing media in the background, which is discussed in the next section). When your activity is resumed or restarted, of course, you need to create a new MediaPlayer and prepare it again before resuming playback.

MediaPlayer会消费宝贵的系统资源,所以必须注意不要保持MediaPlayer实例超过需要的时间。当你用完时,应该调用release()方法来确保分配给它的系统资源被合适的释放了。例如,如果你正在使用MediaPlayer,而Activity收到了onStop()回调,则必须释放MediaPlayer(除非你在后台播放)。当Activity 重新获得焦点或者重新开始时,你需要创建一个新的MediaPlayer实例,并在恢复播放前准备它。

将MediaPlayer释放并制空:

mediaPlayer.release();
mediaPlayer = null;

As an example, consider the problems that could happen if you forgot to release the MediaPlayer when your activity is stopped, but create a new one when the activity starts again. As you may know, when the user changes the screen orientation (or changes the device configuration in another way), the system handles that by restarting the activity (by default), so you might quickly consume all of the system resources as the user rotates the device back and forth between portrait and landscape, because at each orientation change, you create a new MediaPlayer that you never release.

例如,如果你在Activity stop时忘了释放MediaPlayer,但在Activity create时创建了新的实例,那在用户反复旋转屏幕时,可能会很快就耗尽所有的系统资源,因为每次方向改变,你都创建了新的MediaPlayer对象,但从来没有释放。

Using a Service with MediaPlayer

If you want your media to play in the background even when your application is not onscreen—that is, you want it to continue playing while the user is interacting with other applications—then you must start a Service and control the MediaPlayer instance from there. You should be careful about this setup, because the user and the system have expectations about how an application running a background service should interact with the rest of the system. If your application does not fulfil those expectations, the user may have a bad experience. This section describes the main issues that you should be aware of and offers suggestions about how to approach them.

如果想让媒体文件在后台播放,需要启动一个Service,让后再Service中控制MediaPlayer实例。用户和系统对运行后台服务的应用如何同系统其它部分交互有一些期望,如果你的应用无法满足这些期望,用户可能会有糟糕的体验。本节描述了你需要注意的主要事项以及如何解决的建议。

Running asynchronously

First of all, like an Activity, all work in a Service is done in a single thread by default—in fact, if you're running an activity and a service from the same application, they use the same thread (the "main thread") by default. Therefore, services need to process incoming intents quickly and never perform lengthy computations when responding to them. If any heavy work or blocking calls are expected, you must do those tasks asynchronously: either from another thread you implement yourself, or using the framework's many facilities for asynchronous processing.

首先,同Activity一样,默认情况下Service中的所有工作也是在主线程中完成的。因此,服务需要快速的处理传入的intent,在响应意图是不能执行长时间操作。如果有大量的工作或者阻塞式的调用,就需要异步的完成。

For instance, when using a MediaPlayer from your main thread, you should call prepareAsync() rather than prepare(), and implement a MediaPlayer.OnPreparedListener in order to be notified when the preparation is complete and you can start playing. For example:

例如,在主线程中使用MediaPlayer时,你应该调用prepareAsync()而不是prepare(),实现MediaPlayer.OnPreparedListener接口来通知准备已经完成。代码如下:

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();
}
}

Handling asynchronous errors

On synchronous operations, errors would normally be signaled with an exception or an error code, but whenever you use asynchronous resources, you should make sure your application is notified of errors appropriately. In the case of a MediaPlayer, you can accomplish this by implementing a MediaPlayer.OnErrorListener and setting it in your MediaPlayer instance:

在同步的调用中,错误通常是通过异常或者错误码表示,但在异步调用时,你应该确保正确的接收到错误。对于MediaPlayer来说,你可以实现MediaPlayer.OnErrorListener接口,设置给MediaPlayer实例:

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!
}
}

It's important to remember that when an error occurs, the MediaPlayer moves to the Error state (see the documentation for the MediaPlayer class for the full state diagram) and you must reset it before you can use it again.

要记住当错误发生时,MediaPlayer转变为Error状态,在你使用它之前需要重置(reset)它。

学习Android MediaPlayer的更多相关文章

  1. Android(java)学习笔记180:Android MediaPlayer 播放prepareAsync called in state 8解决办法

    使用android MediaPlayer播放音频文件时,有时会出现prepareasync called in state 8错误. 以下方法可以避免这个异常出现.  第一种方法: private ...

  2. Android(java)学习笔记123:Android MediaPlayer 播放prepareAsync called in state 8解决办法

    1. 使用android MediaPlayer播放音频文件时,有时会出现prepareasync called in state 8错误. 以下方法可以避免这个异常出现.  第1种方法: priva ...

  3. 第一部分 Android MediaPlayer 概述

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

  4. Android MediaPlayer架构 -- MediaPlayer的创建过程

    本文系作者自己学习之所用,文章内容仅出自作者拙劣之思考,问题之处烦请不吝指教. MediaPlayer 能被用来控制音/视频文件或流媒体的回放.Android中以MediaPlayer类作为音视频播放 ...

  5. 一培训机构设计的学习android课程内容:供大家参考

    转自:http://www.cnblogs.com/csj007523/archive/2011/06/16/2082682.html 一培训机构设计的学习android课程内容:供大家参考 第一阶段 ...

  6. 想学习Android开发

    最近被别人说知识面窄,心里受伤了.准备学学Android开发,如果能在手机里运行自己写的app,那是多么high ~~~ Android开发需要看什么资料呢? 说明:本人一直从事windows下的C+ ...

  7. 从零开始学习Android(一)Android环境的搭建

    好久没有开始写博客了,最近开始学习Android,所以想把学习的笔记都一一记录下来.一来是方便自己以后资料的查询,其次也是给Android新手朋友进行学习使用,再次也希 望得到高手的指点.废话少说,我 ...

  8. 《IT蓝豹》吹雪花demo,学习android传感器

    吹雪花demo,学习android传感器 吹雪花demo,学习android传感器,嘴巴对着手机底部吹一下就会出现飘着雪花效果. 算是学习android传感器效果.本例子主要是通过android.me ...

  9. 一起来学习Android自定义控件1

    概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...

随机推荐

  1. Max Min Middle

    /*三者中的中间数*/#define Max(a,b) (a>b?a:b) #define Min(a,b) (a<b?a:b) int MiddleOfThree(int a, int ...

  2. DedeCMS标签 PHP判断语句写法

    缩略图标签的判断写法,如果有图片就显示,没图片就显示别的. {dede:field name=litpic runphp='yes'} if(!empty(@me)) { @me="< ...

  3. IOS学习之十七:Grand Central Dispatch(GCD)编程基础

    IOS学习之十七:Grand Central Dispatch(GCD)编程基础   有过编程经验的人,基本都会接触到多线程这块. 在java中以及Android开发中,大量的后台运行,异步消息队列, ...

  4. SJA1000寄存器设置

    在设置CAN控制器SJA1000的输出控制寄存器(OCR)时,由于电路图中只用到了TX0和RX0,所以只考虑OCTP0,OCTN0,OCPOL0.这里设置成了010.然后查了一下配置的表,如下所示: ...

  5. 『局域网安全』利用ARP欺骗劫持Cookie

    0x 00 ARP欺骗说明 欺骗原理相关内容就不多叙述了,百度一大堆 实施ARP欺骗在Windows下,Linux下都相关工具 由于在Linux下可以开启ip_forward功能,个人认为Linux下 ...

  6. 转:Raspberry Pi(树莓派)试用小记

    近期入手一树莓派卡片机,体验了一下它的强大,写篇报告,推广一下哈! 机器截图: 基础参数: CPU:700 MHz, ARM11 内存:512M(还有一种是256M的) 支持GPU加速(高清视频无压力 ...

  7. JDBC连接mysql,TOMCAT错误: Cannot convert value '0000-00-00 00:00:00' from column 10 to TIMESTAMP

    解决思路依据如下URL: http://blog.csdn.net/stail111/article/details/5640109 问题:MySQL数据库,如果数据库中日期字段为空为值为'0000- ...

  8. [LeetCode 114] - 将树平面化为链表(Flatten Binary Tree to Linked List)

    问题 给出一个二叉树,将其原地平面化为链表. 例如,给出: 1   /  \  2    5 / \     \ 3  4     6 平面化后的树看起来应该是这样: 1 \  2    \      ...

  9. java多线程下单例的实现

    Abstract 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制,也就是说只有当使用到这个实例的时候才会创建这个实例,这个好处在单例模式中得到了广泛应用.这个机制在s ...

  10. Android中设置文字大小的定义类型

    在Android中所有的组件可以设置大小,但是在设置大小的时候需要指定其单位,这些单位如下: px(pixels):像素: dip(device independent pixels):依赖于设备的像 ...