从资产目录播放音频文件

143

我有以下代码:

AssetFileDescriptor afd = getAssets().openFd("AudioFile.mp3");
player = new MediaPlayer();
player.setDataSource(afd.getFileDescriptor());
player.prepare();
player.start();

问题在于,当我运行这段代码时,它会按字母顺序播放 assets 目录中的所有音频文件,而不是只播放我请求的音频文件。我做错了什么?有没有更好的方法从 assets 目录播放音频文件?

后续问题: 将音频文件保存在 assets 目录和 res/raw 目录中有什么区别?除了保存在 assets 目录中不会获得 id。如果我将音频文件移动到 res/raw 目录,则在重用 MediaPlayer 时会出现问题,因为 setDataSource() 没有 id 参数。我找不到处理此类问题的良好指南。

6个回答

252
player.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(),afd.getLength());

如果你在assets目录中只有一个文件,那么你的版本会起作用。实际上,assets目录中的内容并不是磁盘上的“真实文件”。所有文件都会一个接一个地放在一起。因此,如果您不指定从哪里开始读取多少字节,播放器将一直读取到结尾(即播放assets目录中的所有文件)。


1
可以了,谢谢。但是我认为我的版本也应该可以工作。 - Catalin Morosan
61
如果您的资产目录中只有一个文件,那么您的版本将有效。实际上,资产目录中的内容并不是磁盘上的“真实文件”,而是一个接一个地放在一起。因此,如果您没有指定从哪里开始读取和需要读取多少字节,播放器将一直读取到结尾(也就是播放资产目录中的所有文件)。 - Sarwar Erfan
1
这是我使用的代码路径,但它不起作用:https://dev59.com/72DVa4cB1Zd3GeqPYwDu - Timothy Lee Russell
1
+1 是为了回答我关于资产文件完全无关的问题! - jjm
@SarwarErfan,当我尝试使用这个方法时,出现了“java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed”的错误,有没有什么办法可以解决这个问题? - seaders
显示剩余2条评论

81

这个函数将正常工作 :)

// MediaPlayer m; /*assume, somewhere in the global scope...*/

public void playBeep() {
    try {
        if (m.isPlaying()) {
            m.stop();
            m.release();
            m = new MediaPlayer();
        }

        AssetFileDescriptor descriptor = getAssets().openFd("beepbeep.mp3");
        m.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
        descriptor.close();

        m.prepare();
        m.setVolume(1f, 1f);
        m.setLooping(true);
        m.start();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3
m是什么?你在初始化m = new MediaPlayer()之后就使用了它,是吗? - Umer
嗨@Umar,我已经定义了全局变量MediaPlayer m = null; 然后在playBeep()函数中进行了赋值。 - Siddhpura Amit
请记住,MediaPlayer m 必须是 static 或具有另一个引用。如果您在没有任何引用的函数中使用 m,则 GC 将“收集”它。 - Menelaos Kotsollaris
有时音频无法播放到最后。 - Roman Soviak
循环到真是永远播放吗? - gumuruh

8

这里输入图片描述

开始声音

startSound("mp3/ba.mp3");

方法

private void startSound(String filename) {
    AssetFileDescriptor afd = null;
    try {
        afd = getResources().getAssets().openFd(filename);
    } catch (IOException e) {
        e.printStackTrace();
    }
    MediaPlayer player = new MediaPlayer();
    try {
        assert afd != null;
        player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        player.prepare();
    } catch (IOException e) {
        e.printStackTrace();
    }
    player.start();
}

当文件位于资产目录的子文件夹中时,这将非常有用。谢谢。 - Abdu

8

这是我的静态版本:

public static void playAssetSound(Context context, String soundFileName) {
    try {
        MediaPlayer mediaPlayer = new MediaPlayer();

        AssetFileDescriptor descriptor = context.getAssets().openFd(soundFileName);
        mediaPlayer.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
        descriptor.close();

        mediaPlayer.prepare();
        mediaPlayer.setVolume(1f, 1f);
        mediaPlayer.setLooping(false);
        mediaPlayer.start();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2

修复上述函数的播放和暂停功能

  public void playBeep ( String word )
{
    try
    {
        if ( ( m == null ) )
        {

            m = new MediaPlayer ();
        }
        else if( m != null&&lastPlayed.equalsIgnoreCase (word)){
            m.stop();
            m.release ();
            m=null;
            lastPlayed="";
            return;
        }else if(m != null){
            m.release ();
            m = new MediaPlayer ();
        }
        lastPlayed=word;

        AssetFileDescriptor descriptor = context.getAssets ().openFd ( "rings/" + word + ".mp3" );
        long                start      = descriptor.getStartOffset ();
        long                end        = descriptor.getLength ();

        // get title
        // songTitle=songsList.get(songIndex).get("songTitle");
        // set the data source
        try
        {
            m.setDataSource ( descriptor.getFileDescriptor (), start, end );
        }
        catch ( Exception e )
        {
            Log.e ( "MUSIC SERVICE", "Error setting data source", e );
        }

        m.prepare ();
        m.setVolume ( 1f, 1f );
        // m.setLooping(true);
        m.start ();
    }
    catch ( Exception e )
    {
        e.printStackTrace ();
    }
}

-5

这对我有效:

public static class eSound_Def
{
  private static Android.Media.MediaPlayer mpBeep;

  public static void InitSounds( Android.Content.Res.AssetManager Assets )
  {
    mpBeep = new Android.Media.MediaPlayer();

    InitSound_Beep( Assets );
  }

  private static void InitSound_Beep( Android.Content.Res.AssetManager Assets )
  {
    Android.Content.Res.AssetFileDescriptor AFD;

    AFD = Assets.OpenFd( "Sounds/beep-06.mp3" );
    mpBeep.SetDataSource( AFD.FileDescriptor, AFD.StartOffset, AFD.Length );
    AFD.Close();

    mpBeep.Prepare();
    mpBeep.SetVolume( 1f, 1f );
    mpBeep.Looping = false;
  }

  public static void PlaySound_Beep()
  {
    if (mpBeep.IsPlaying == true) 
    {
      mpBeep.Stop();
      mpBeep.Reset();
      InitSound_Beep(); 
    }
    mpBeep.Start();
  }
}

在主活动中,onCreate:
protected override void OnCreate( Bundle savedInstanceState )
{
  base.OnCreate( savedInstanceState );
  SetContentView( Resource.Layout.lmain_activity );
  ...
  eSound_Def.InitSounds( Assets );
  ...
}

如何在代码中使用(在按钮点击时):

private void bButton_Click( object sender, EventArgs e )
{
  eSound_Def.PlaySound_Beep();
}

什么是eUNIS? - Dyno Cris
eUNIS是一个自定义的静态类,其中包含变量Assets,它是应用程序资源的引用。 - Altivo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接