65.9K
CodeProject 正在变化。 阅读更多。
Home

为 Android 应用添加背景音乐

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.89/5 (9投票s)

2011年9月21日

CPOL

5分钟阅读

viewsIcon

248013

downloadIcon

14769

本文解释了如何在开发 Android 应用(例如游戏)时添加背景音乐。

引言

Android 应用开发的大部分内容是游戏开发。背景音乐是游戏应用的重要组成部分。本文将介绍如何使用 Android SDK 库提供的 MediaPlayer 为任何 Android 应用添加音乐。假定您熟悉 Android Activity 和 Service。

背景

MediaPlayer 类控制音频/视频文件和流的播放。
它的生命周期以状态机图的形式实现。官方 Android 开发页面对它的生命周期有很好的解释。我建议您通过阅读该页面来熟悉 MediaPlayer 的生命周期。MediaPlayer 必须处于准备状态才能播放音乐。通常,媒体源可以是:本地资源、内部 URI,例如您可能从 Content Resolver 获取的 URI、外部 URL(流式传输)。
我们感兴趣的是使用本地资源。因此,请将您的应用程序的音乐文件保存在 /res/raw 目录中。支持的各种音乐音频文件如下:
MP3、MIDI、WAV、MP4、MP4A、3GP、FLAC、ADTS Raw AAC(.aac 仅解码)。

将 Service 与 MediaPlayer 一起使用

为了在用户与您的应用交互时在后台播放媒体,您必须从应用程序的主 Activity 启动一个 Service,该 Service 将包含所有与播放相关的函数。为了让 Activity 与 Service 交互,还需要一个 Service 连接。简而言之,我们需要实现一个绑定 Service。

总的来说,由于各种原因,播放控制操作可能会失败,例如不支持的音视频格式、音视频交错不良、分辨率过高、流式传输超时、编程错误等。因此,请包含足够多的错误处理和恢复机制。在所有这些错误条件下,如果之前通过 setOnErrorListener(android.media.MediaPlayer.OnErrorListener) 注册了 OnErrorListener ,内部播放器引擎将调用用户提供的 OnErrorListener.onError() 方法。即使没有注册错误监听器,MediaPlayer 也会进入“Error”状态。因此,对于媒体播放器的错误处理机制,必须充分理解媒体播放器的状态图。

Using the Code

以下是实现媒体播放器的基本 Service 的代码。代码使用 Eclipse IDE 中的 Android SDK 用 Java 编写。将此代码复制为名为 MusicService.class 的单独 Java 文件,放在您的 Android 应用程序的 src 目录下。我在应用程序中播放的示例音乐也可作为“jingle.mp3”下载,应存储在“res/raw”目录下。

由于这是一个允许其他应用程序组件绑定和与之交互的绑定 Service,因此我们必须实现 onBind() 回调方法。有关绑定 Service 的更多详细信息超出了本文档的范围,因为它主要处理 MediaPlayer 的实现,并假定您对 Service 有良好的理解。

以下是此处实现的重要术语和函数,其余内容不言自明

  1. Service 实现 onErrorListener 以进行错误处理和恢复。
  2. mBinder:一个 IBinder 对象,客户端将使用它与 Service 交互。
  3. 构造函数是空的,因为我在这里只演示背景音乐功能。但是,根据您的应用程序,您可以在此处执行一些初始化。
  4. Class ServiceBinder:由于此 Service 对应用程序是私有的,并且与客户端在同一进程中运行,因此您应该通过扩展 Binder 类来创建自己的接口,并在 onBind() 中返回它的实例。客户端接收 Binder 并可以使用它来直接访问 Binder 实现或甚至 Service 中可用的 public 方法。
  5. onCreate():在这里,我们通过调用 mPlayer.create() 并将音乐文件的路径作为参数来创建 MediaPlayer。调用 create 时,MediaPlayer 已处于准备状态,因此无需显式准备播放器。
    此外,由于音乐需要不间断播放,因此将其设置为循环播放,并使用 setVolume 设置初始音量。还注册了 errorListener ,并在出现错误时调用 onError() 函数。您可以在此处编写错误处理代码。在我的代码中,发生错误时会停止播放器并释放对象。
  6. onStartCommand:在此处开始播放器,我们返回 START_STICKY,因为音乐必须在整个应用程序中持续播放,除非用户暂停或停止。

其余函数简单明了。

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnErrorListener;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;

public class MusicService extends Service  implements MediaPlayer.OnErrorListener{

    private final IBinder mBinder = new ServiceBinder();
    MediaPlayer mPlayer;
    private int length = 0;

    public MusicService() { }

    public class ServiceBinder extends Binder {
     	 MusicService getService()
    	 {
    		return MusicService.this;
    	 }
    }

    @Override
    public IBinder onBind(Intent arg0){return mBinder;}

    @Override
    public void onCreate (){
	  super.onCreate();

       Player = MediaPlayer.create(this, R.raw.jingle);
       mPlayer.setOnErrorListener(this);

       if(mPlayer!= null)
        {
        	mPlayer.setLooping(true);
        	mPlayer.setVolume(100,100);
        }


        mPlayer.setOnErrorListener(new OnErrorListener() {

	  public boolean onError(MediaPlayer mp, int what, int
          extra){

			onError(mPlayer, what, extra);
			return true;
		}
    	  });
	}

    @Override
	public int onStartCommand (Intent intent, int flags, int startId)
	{
         mPlayer.start();
         return START_STICKY;
	}

	public void pauseMusic()
	{
		if(mPlayer.isPlaying())
		{
			mPlayer.pause();
			length=mPlayer.getCurrentPosition();

		}
	}

	public void resumeMusic()
	{
		if(mPlayer.isPlaying()==false)
		{
			mPlayer.seekTo(length);
			mPlayer.start();
		}
	}

	public void stopMusic()
	{
		mPlayer.stop();
		mPlayer.release();
		mPlayer = null;
	}

	@Override
	public void onDestroy ()
	{
		super.onDestroy();
		if(mPlayer != null)
		{
		try{
		 mPlayer.stop();
		 mPlayer.release();
			}finally {
				mPlayer = null;
			}
		}
	}

	public boolean onError(MediaPlayer mp, int what, int extra) {

		Toast.makeText(this, "music player failed", Toast.LENGTH_SHORT).show();
		if(mPlayer != null)
		{
			try{
				mPlayer.stop();
				mPlayer.release();
			}finally {
				mPlayer = null;
			}
		}
		return false;
	}

将 Activity 绑定到 Service

在您的应用程序的 Activity 类(Java 文件)中,使用以下代码建立 Service 连接:

private boolean mIsBound = false;
private MusicService mServ;
private ServiceConnection Scon =new ServiceConnection(){

	public void onServiceConnected(ComponentName name, IBinder
     binder) {
	mServ = ((MusicService.ServiceBinderbinder).getService();
	}

	public void onServiceDisconnected(ComponentName name) {
		mServ = null;
	}
	};

	void doBindService(){
 		bindService(new Intent(this,MusicService.class),
				Scon,Context.BIND_AUTO_CREATE);
		mIsBound = true;
	}

	void doUnbindService()
	{
		if(mIsBound)
		{
			unbindService(Scon);
      		mIsBound = false;
		}
	}

在上面的代码中,我创建了一个 Service 连接 Scon,它在 onServiceConnected() 中获取要调用的 Service 到 mServ 变量中,并在 Service 断开连接后将其设置为 nulldoBindServicedoUnbindService 分别用于绑定和解除绑定到 Service。有一个布尔标志 mIsBound,在 Service 绑定到 Activity 时会被设置。

开始、暂停、恢复和停止音乐

请按照以下步骤操作:

第 1 步:首先,通过在 Activity 的 onCreate 中调用 doBindService 并将 Intent 传递给 Service 来绑定 Service。

第 2 步:通过显式 Intent 启动 Service。

Intent music = new Intent();
music.setClass(this,MusicService.class);
startService(music);

第 3 步:在您的 Activity 中,无论何时想暂停、恢复或停止音乐,请按如下方式调用相应的 Service 函数:

mServ.pauseMusic();
mServ.resumeMusic();
mServ.stopMusic();

第 4 步:不要忘记在您想将 Service 从 Activity 解绑的地方调用 doUnbindService。理想的位置是调用 Activity 的 onDestroy() 方法。

第 5 步:在您的应用程序的 androidmanifest 文件中,粘贴以下 XML 代码:

"service android:name="MusicService"android:enabled="true" 

历史

  • 2011 年 9 月 19 日:初始版本
  • 2011 年 9 月 22 日:添加了第 5 步
© . All rights reserved.