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

在Fragment/标签页中用SoundPool开发音效板应用遇AudioManager获取问题

问题排查与修复方案

我帮你梳理了代码里的几个关键问题,这些应该是导致应用无法正常运行的核心原因:

主要问题点

  • Fragment调用getSystemService方式错误:Fragment本身没有getSystemService方法,必须通过getActivity()来获取系统服务,直接调用会引发运行时异常。
  • getView()调用时机过早:在onCreateView中还未返回view时调用getView()会返回null,导致空指针崩溃,应该用已inflate的view对象来查找控件。
  • 重复设置SoundPool加载完成监听器:代码中两次设置OnLoadCompleteListener,第二次会覆盖第一次,属于冗余操作。
  • 自定义方法覆盖系统方法:你写的空实现setVolumeControlStream覆盖了Fragment继承的系统方法,导致无法正确设置音量控制流,需要删除这个自定义方法。
  • Context初始化时机错误:在Fragment构造方法中调用getContext()会返回null,因为此时Fragment还未依附到Activity上,应在生命周期方法内获取Context。
  • AudioManager常量引用错误:audiomanager.STREAM_MUSIC是错误的写法,这个是静态常量,应该用AudioManager.STREAM_MUSIC。

修正后的完整代码

public class FragmentQuiz extends android.support.v4.app.Fragment {
    ListView listView;
    int[] soundArray;
    private SoundPool soundPool;
    private int MAX = 1;
    View view;
    boolean loaded = false;

    public FragmentQuiz() {
        // 构造方法中不要初始化Context或调用依赖Activity的方法
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.quiz_fragment, container, false);

        // 通过Activity设置音量控制流
        getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);

        // 初始化SoundPool
        soundPool = new SoundPool(MAX, AudioManager.STREAM_MUSIC, 0);
        soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                loaded = true;
            }
        });

        // 加载音效文件
        soundArray = new int[3]; // 你只加载了3个音效,数组长度设为3更合理
        soundArray[0] = soundPool.load(getActivity(), R.raw.bird, 1);
        soundArray[1] = soundPool.load(getActivity(), R.raw.rooster, 1);
        soundArray[2] = soundPool.load(getActivity(), R.raw.elephant, 1);

        // 获取AudioManager(通过Activity调用getSystemService)
        AudioManager audioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
        float actualVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
        float maxVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        final float volume = actualVolume / maxVolume;

        // 通过已inflate的view查找ListView
        listView = view.findViewById(R.id.list);
        String[] values = new String[]{
                "Android Lollipop",
                "beta",
                "marshmello"
        };
        ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
                android.R.layout.simple_list_item_1,
                android.R.id.text1,
                values);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                int itemPosition = position;
                String itemValue = (String) listView.getItemAtPosition(position);
                Toast.makeText(getActivity(),
                        "position: " + itemPosition + " ListItem: " + itemValue,
                        Toast.LENGTH_SHORT).show();

                // 播放音效前先判断是否加载完成
                if (loaded && position < soundArray.length) {
                    soundPool.play(soundArray[position], volume, volume, 1, 0, 1f);
                }
            }
        });

        return view;
    }

    // 删除自定义的setVolumeControlStream方法,使用系统提供的方法
}

额外优化点

  • 我在播放音效前增加了loaded状态和数组边界的判断,避免音效未加载完成或点击位置超出数组长度时引发异常。
  • 调整了soundArray的长度,因为你只加载了3个音效,原来的长度5会造成不必要的内存浪费。
  • 简化了Context的使用,直接用getActivity()即可,不需要额外调用getApplicationContext(),在Fragment中使用宿主Activity的Context更合适。

内容的提问来源于stack exchange,提问作者Pranesh Nangare

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:06:35