You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Java词典应用:dictionaryapi.dev音频播放失败求助

DictionaryAPI音频播放问题排查与解决方案

问题详情

  • 开发环境:Android Java词典应用,基于Retrofit获取DictionaryAPI数据,RecyclerView展示内容
  • 错误表现:点击音频图标播放https://api.dictionaryapi.dev/media/pronunciations/en/{word}-us.mp3时,Logcat输出错误:
    E/MediaPlayerNative: error (1, -2147483648)
    E/MediaPlayer: Error (1,-2147483648)
    E/AUDIO_ERROR: MediaPlayer exception: null
    
  • 验证情况:其他第三方音频链接(MP3/WAV/FLAC/OGG格式)均可正常播放,仅该API的音频链接失效

相关代码

public class PhoneticAdapter extends RecyclerView.Adapter<PhoneticVH> {
    private final Context context;
    private List<Phonetic> phoneticList;
    private MediaPlayer player;

    public PhoneticAdapter(Context context, List<Phonetic> phoneticList) {
        this.context = context;
        this.phoneticList = phoneticList;
    }


    @NonNull
    @Override
    public PhoneticVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new PhoneticVH(LayoutInflater.from(context).inflate(R.layout.phonetic_list_items, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull PhoneticVH holder, @SuppressLint("RecyclerView") int position) {
        holder.phonetic_text.setText(phoneticList.get(position).getText());
        holder.phonetic_audio.setOnClickListener(view -> {
//            String audioUrl = "https://" + phoneticList.get(position).getAudio();
            player = new MediaPlayer();
            try{
                AudioAttributes audioAttributes = new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_MEDIA)
                        .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                        .build();

                player.setAudioAttributes(audioAttributes);
//                player.setDataSource("https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3");
//                player.setDataSource("https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3");
//                player.setDataSource("https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba-online-audio-converter.com_-1.wav");
//                player.setDataSource("https://www.learningcontainer.com/wp-content/uploads/2020/02/Sample-FLAC-File.flac");
//                player.setDataSource("https://www.learningcontainer.com/wp-content/uploads/2020/02/Sample-OGG-File.ogg");
                player.setDataSource("https://" + phoneticList.get(position).getAudio());
                player.setOnPreparedListener(mp -> {
                    mp.start();
                });
                player.setOnErrorListener((mediaPlayer, i, i1) -> {
                    Log.e("AUDIO_ERROR", "MediaPlayer error: " + i);
                    Toast.makeText(context, "Error: " + i, Toast.LENGTH_SHORT).show();
                    return false;
                });
                player.prepareAsync();
                player.prepare();
                player.start();
            }catch (Exception e){
                Log.e("AUDIO_ERROR", "MediaPlayer exception: " + e.getMessage());
                Toast.makeText(context, R.string.audio_fail, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        if (phoneticList == null) {
            return 0;
        }
        return phoneticList.size();
    }

    @SuppressLint("NotifyDataSetChanged")
    public void setData(List<Phonetic> phoneticList) {
        this.phoneticList = phoneticList;
        notifyDataSetChanged();
    }
}

问题排查与解决

1. 先修复代码本身的错误

你的代码中同时调用了prepareAsync()和prepare(),这两个方法互斥:

  • prepareAsync()是异步加载音频,需通过OnPreparedListener回调触发播放
  • prepare()是同步加载,会阻塞线程

同时调用会直接导致MediaPlayer异常,这是当前报错的核心原因之一。修改后的播放逻辑如下:

holder.phonetic_audio.setOnClickListener(view -> {
    // 先释放旧的MediaPlayer实例,避免内存泄漏
    if (player != null) {
        player.release();
        player = null;
    }
    player = new MediaPlayer();
    try{
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // 发音用SPEECH更合适
                .build();

        player.setAudioAttributes(audioAttributes);
        String audioUrl = "https://" + phoneticList.get(position).getAudio();
        player.setDataSource(audioUrl);
        
        player.setOnPreparedListener(mp -> mp.start());
        player.setOnErrorListener((mediaPlayer, errorCode, extraCode) -> {
            Log.e("AUDIO_ERROR", "错误码: " + errorCode + ", 额外码: " + extraCode);
            Toast.makeText(context, R.string.audio_fail, Toast.LENGTH_SHORT).show();
            // 释放异常的MediaPlayer
            mediaPlayer.release();
            return true;
        });
        // 仅调用异步准备,避免阻塞UI线程
        player.prepareAsync();
    }catch (Exception e){
        Log.e("AUDIO_ERROR", "播放异常: " + e.getMessage());
        Toast.makeText(context, R.string.audio_fail, Toast.LENGTH_SHORT).show();
        if (player != null) {
            player.release();
            player = null;
        }
    }
});

2. 若问题源于API的处理方案

如果修复代码后仍无法播放,大概率是API返回的音频存在兼容性问题:

  • 验证音频有效性:直接在浏览器中打开目标音频链接,确认是否能正常下载播放;若返回404/403,说明API无该词的发音资源
  • 替换播放器:Android原生MediaPlayer对某些MP3编码(如特定比特率、采样率)支持有限,推荐改用ExoPlayer,它支持更多音频格式和流协议,兼容性更好
  • 缓存音频到本地:先通过OkHttp将音频下载到本地,再用MediaPlayer播放本地文件,绕开在线流的兼容性问题

3. 更换音频链接的对接方案

若要替换为其他词典API的音频源,只需调整以下环节:

  • Retrofit数据解析:修改接口返回的实体类(Phonetic),将新API的音频链接字段映射到audio属性
  • 保持播放逻辑不变:修复后的MediaPlayer/ExoPlayer播放逻辑无需改动,只要phoneticList.get(position).getAudio()能返回有效的音频链接即可
  • 适配新链接格式:如果新API的音频链接已包含https://前缀,去掉代码中手动拼接的"https://",避免重复拼接导致无效链接

内容的提问来源于stack exchange,提问作者Sana Momin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:10:03