android - 如何从 mp3 数组播放音频 [Android]
问题描述
在一个测试项目上工作,我目前的目标是使用一个 int 来指定在应用程序初始化时播放哪个 mp3 文件,而无需事先知道音轨的名称(可伸缩性问题,因为我希望能够将新的 mp3 文件添加到将来不接触代码的随机化池)。但是,当我运行以下代码时,出现以下描述的错误:
错误:找不到合适的方法 create(MainActivity,String) 方法 MediaPlayer.create(Context,Uri) 不适用(参数不匹配;字符串无法转换为 Uri)方法 MediaPlayer.create(Context,int) 不适用(参数不匹配;字符串不能转换为 int)
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.widget.ArrayAdapter;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
RecyclerView bensonRecycler;
ArrayList<String> arrayList;
ArrayAdapter bensonAdapter;
MediaPlayer bensonPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AssetManager assetManager = getAssets();
String[] audios = assetManager.list("sound");
int i = 1;
final MediaPlayer mp = MediaPlayer.create(this, audios[i]);
mp.start();
}
}
我的 mp3 文件资产具有以下结构:
所以我的问题是我应该怎么做才能使用 int i在 mp3 资产数组中指定要播放的 mp3 音轨(事先不知道 mp3 音轨的名称) ?(我必须使用一个变量来指定要在这个测试项目中播放的音轨)
解决方案
“资产”文件夹根本不是真正的文件夹,而是捆绑的字节流。这就是为什么有AssetManager。
AssetManager
提供对应用程序原始资产文件的访问;有关大多数应用程序想要检索其资源数据的方式,请参阅资源。此类提供了一个较低级别的 API,允许您以简单的字节流形式打开和读取与应用程序捆绑在一起的原始文件。
AssetManager让我们可以轻松地构建文件的字符串数组,并且我们可以将这些文件视为属于小型文件系统。诀窍是如何呈现这些文件(实际上是字节流),MediaPlayer
以便可以根据声音资产的索引播放声音。
以下代码将播放索引声音。代码中的注释解释了它是如何工作的。为了进行测试,我刚刚构建了一个简单的布局,其中包含三个按钮,它们在索引 0、1 和 2 处播放声音。
主要活动
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private void playSoundFromAssets(int index) {
try {
AssetManager assetManager = getAssets();
String[] audios = assetManager.list(SOUNDFILE_PATH);
if (audios == null || index >= audios.length) {
return;
}
String soundFilePath = new File(SOUNDFILE_PATH, audios[index]).getPath();
AssetFileDescriptor afd = getAssets().openFd(soundFilePath);
final MediaPlayer mp = new MediaPlayer();
/* For API 24+, we can just use the AssetFileDescriptor to play the sound. However,
for API 23-, we can't use the AssetFileDescriptor directly but can retrieve a
FileDescriptor from it that points to the beginning of our assets. The offset
and length from the AssetFileDescriptor serve for the FileDescriptor as well.
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mp.setDataSource(afd);
} else {
FileDescriptor fd = afd.getFileDescriptor();
Log.d("MainActivity", String.format("<<<< %s %d %d", soundFilePath, afd.getStartOffset(), afd.getLength()));
mp.setDataSource(fd, afd.getStartOffset(), afd.getLength());
// One might think that mp.setDataSource(fd) would play the sound file we want, but
// it actually plays all sound files one after another. It seems that fd is a
// FileDescriptor that points to the beginning of the assets.
}
afd.close();
mp.prepare();
mp.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public void playSound(View view) {
switch (view.getId()) {
case R.id.play0:
playSoundFromAssets(0);
break;
case R.id.play1:
playSoundFromAssets(1);
break;
case R.id.play2:
playSoundFromAssets(2);
break;
}
}
private static final String SOUNDFILE_PATH = "sound";
}
推荐阅读
- javascript - 单击按钮后显示另一个(永久)按钮
- yii - 在yii2的where条件中使用字段作为递归函数
- javascript - 如何在 ng-options 或 ng-repeat 中使用 *ngFor="let e of employees"
- virtualbox - 哪个协议使用 Virtualbox 代理?
- xml - XSL:FO 流式行内引用
- graphql - 如何使用 GraphQL 放置/更新嵌套数据?
- javascript - 显示递归请求的进度
- c# - 如何从 .NET Core 调用 cygwin 编译的 C++?
- kubernetes - Kubernetes:配置快照
- java - 您是否需要多个 asynctask 来运行多个任务?