找不到类' android.media.AudioAttributes $ Builder'

时间:2015-05-15 13:15:39

标签: java android api audio classloader

所以我现在正在为我正在进行的游戏实现播放声音。现在游戏支持API 8到最新的21.我使用SoundPool来播放和处理声音,但似乎使用API​​ 21,你必须为SoundPool设置AudioAttributes。

我目前收到以下错误:

  

05-15 13:56:48.202   26245-26245 / thedronegame.group08.surrey.ac.uk.thedronegame E / dalvikvm:   找不到类' android.media.AudioAttributes $ Builder',   从方法中引用   thedronegame.group08.surrey.ac.uk.thedronegame.Sound.initializeRecentAPISoundPool

声音等级

<pre>package thedronegame.group08.surrey.ac.uk.thedronegame;

import android.annotation.TargetApi;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.media.MediaPlayer;
import android.os.Build;
import android.util.Log;

/**
 * Created by Michael on 19/03/15.
 */
public class Sound {

    /**
     * The sound pool
     */
    private SoundPool soundPool = null;


    /**
     * The current Sound.
     */
    private int sound = 0;

    /**
     * false Boolean.
     */
    private boolean loaded = false;

    /**
     * The context.
     */
    private Context context = null;

    /**
     * Audio Manager.
     */
    private AudioManager audioManager = null;

    /**
     * Literal Volume.
     */
    private float literalVolume = 0;

    /**
     * Maximum Volume.
     */
    private float maximumVolume = 0;

    /**
     * Volume.
     */
    private float volume = 0;

    /**
     * A constructor for creating a new Sound object
     */
    public Sound(Context context) {

        this.context = context;

        this.audioManager = (AudioManager) context.getSystemService(context.AUDIO_SERVICE);

        // Set Literal Volume for Audio Manager.
        this.literalVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

        // Set Maximum Volume for Audio Manager.
        this.maximumVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);

        // Set volume for GameSound Pool.
        this.volume = literalVolume / maximumVolume;
    }

    /**
    
     * Initialize the SoundPool for later API versions
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void initializeRecentAPISoundPool() {
        // Create AudioAttributes.


        AudioAttributes attributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_GAME)
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .build();

        this.soundPool = new SoundPool.Builder()
                .setAudioAttributes(attributes)
                .setMaxStreams(7)
                .build();
    }

    /**
    
     * Intialize SoundPool for older API
     versions
     */
    @SuppressWarnings("deprecation")
    private void initializeDeprecatedAPISoundPool() {
        // Initialize SoundPool.
        this.soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC,0);
    }

    /**
    
     * Load Sounds into the SoundPool.
    
     */
    private void loadIntoSoundPool() {
        //todo: finish loadIntoSoundPool() method

        // Loads all sounds from array

        // Sound 0.
        this.soundPool.load(this.context, R.raw.blip_select2, 0);

        // Sound 1.
        //this.soundPool.load(context, R.raw.sound, 1);
    }

    /**
     * Set the initial SoundPool.
    
     *  Call to Method differs dependent on API Version.
    
     */
    public void setInitialSoundPool() {

        // Initialize SoundPool, call specific dependent on SDK Version
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            initializeRecentAPISoundPool();
        }
        else {
            initializeDeprecatedAPISoundPool();
        }

        this.soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {

            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                loaded = true;
                soundPool.load(context, R.raw.blip_select2, 0);
            }
        });

        // Load sounds into sound pool from resources.
        //this.loadIntoSoundPool();

    }

    /**
     * Plays the sound
     * @param id - the sound id
     * @param context - the context
     */
    public void playSound(int id, final Context context) {
        // Create Audio Manager using Context.

        soundPool.play(id, this.volume, this.volume, 1, 0, 1f);


        // Play GameSound from GameSound Pool with defined Volumes.


        Log.e("SoundPool", "Game GameSound Played");
    }
}</code>

有没有人遇到这个问题?非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

谢谢David Wasser :)

我想与大家分享最终的实现,以及目前适用于API 21和Lower的内容。

在为API 21 +构建SoundPool时发现,您必须先创建AudioAttributes:

    Log.d("Sound", "Initialize Audio Attributes.");
    // Initialize AudioAttributes.
    AudioAttributes attributes = new AudioAttributes.Builder()
            .setUsage(AudioAttributes.USAGE_GAME)
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .build();

在构建AudioAttributes后,您可以使用Sound.Builder初始化SoundPool:

    Log.d("Sound", "Set AudioAttributes for SoundPool.");
    // Set the audioAttributes for the SoundPool and specify maximum number of streams.
    soundPool = new SoundPool.Builder()
            .setAudioAttributes(attributes)
            .setMaxStreams(7)
            .build();

请注意,正如David Wasser指出的那样,此AudioAttributes必须与默认类的类别分开,以便处理声音,因为API 21不兼容AudioAttributes - 兼容设备因此会报告错误。我为API 21 SoundPool和AudioAttributes实现创建了一个类:

<强> SoundRecent.java

    import android.annotation.TargetApi;
    import android.media.AudioAttributes;
    import android.media.SoundPool;
    import android.os.Build;
    import android.util.Log;

    /**
     * Created by michaelstokes on 17/05/15.
     */
    public class SoundRecent {

        /**
        
         * Initialize the SoundPool for later API versions
         */
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public SoundPool initializeRecentAPISoundPool(SoundPool soundPool) {

        Log.d("Sound", "Initialize Audio Attributes.");
        // Initialize AudioAttributes.
        AudioAttributes attributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_GAME)
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .build();

        Log.d("Sound", "Set AudioAttributes for SoundPool.");
        // Set the audioAttributes for the SoundPool and specify maximum number of streams.
        soundPool = new SoundPool.Builder()
                .setAudioAttributes(attributes)
                .setMaxStreams(7)
                .build();

        return soundPool;
    }
}

**对于您的原始SoundClass,将调用Devices API版本以及相应的初始化程序:**

    package thedronegame.group08.surrey.ac.uk.thedronegame;

import android.annotation.TargetApi;
import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
import android.util.Log;

/**
 * Created by Michael on 19/03/15.
 */
public class Sound {

    /**
     * The sound pool
     */
    private SoundPool soundPool = null;


    /**
     * The current Sound.
     */
    private int sound = 0;

    /**
     * false Boolean.
     */
    private boolean loaded = false;

    /**
     * The context.
     */
    private Context context = null;

    /**
     * Audio Manager.
     */
    private AudioManager audioManager = null;

    /**
     * Literal Volume.
     */
    private float literalVolume = 0;

    /**
     * Maximum Volume.
     */
    private float maximumVolume = 0;

    /**
     * Volume.
     */
    private float volume = 0;

    /**
     * A constructor for creating a new Sound object
     */
    public Sound(Context context) {

        this.context = context;

        this.audioManager = (AudioManager) context.getSystemService(context.AUDIO_SERVICE);

        // Set Literal Volume for Audio Manager.
        this.literalVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

        // Set Maximum Volume for Audio Manager.
        this.maximumVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);

        // Set volume for GameSound Pool.
        this.volume = literalVolume / maximumVolume;

    }

    /**
    
     * Initialize the SoundPool for later API versions
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void initializeRecentAPISoundPool() {

        Log.d("SoundPool", "Initialize recent API Sound Pool");
        this.soundPool = new SoundRecent().initializeRecentAPISoundPool(this.soundPool);
    }

    /**
    
     * Intialize SoundPool for older API
     versions
     */
    @SuppressWarnings("deprecation")
    private void initializeDeprecatedAPISoundPool() {
        // Initialize SoundPool.
        this.soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
    }

    /**
    
     * Load Sounds into the SoundPool.
    
     */
    private void addSoundsToSoundPool() {

        Log.d("Sound", "Load Sounds.");

        int soundID = 0;

        // Load Sound 1
        soundID = soundPool.load(context, R.raw.blip_select2, 1);
        Log.d("Sound", "Sound " + soundID + " Loaded.");

        // Load Sound 2
        soundID = soundPool.load(context, R.raw.pickup_coin3, 1);
        Log.d("Sound", "Sound " + soundID + " Loaded.");

        // Load Sound 3
        soundID = soundPool.load(context, R.raw.explosion2, 1);
        Log.d("Sound", "Sound " + soundID + " Loaded.");

        // Load Sound 4
        soundID = soundPool.load(context, R.raw.powerup8, 1);
        Log.d("Sound", "Sound " + soundID + " Loaded.");

        // Load Sound 5
        soundID = soundPool.load(context, R.raw.powerup15, 1);
        Log.d("Sound", "Sound " + soundID + " Loaded.");

        // Load Sound 6
        soundID = soundPool.load(context, R.raw.jump9, 1);
        Log.d("Sound", "Sound " + soundID + " Loaded.");

        // Load Sound 7
        soundID = soundPool.load(context, R.raw.powerup18, 1);
        Log.d("Sound", "Sound " + soundID + " Loaded.");
    }

    /**
     * Set the initial SoundPool.
    
     *  Call to Method differs dependent on API Version.
    
     */
    public void setInitialSoundPool() {

        Log.d("Sound", "Initialize Recent or Deprecated API SoundPool.");

        // Initialize SoundPool, call specific dependent on SDK Version
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Log.d("Sound", "Initialize Recent API SoundPool.");
            initializeRecentAPISoundPool();
        }
        else {
            Log.d("Sound", "Initialize Old API SoundPool.");
            initializeDeprecatedAPISoundPool();
        }

        this.soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {

            @Override
            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
                loaded = true;
            }
        });

        // Add and Load sounds into SoundPool.
        this.addSoundsToSoundPool();
    }

    /**
     * Plays the sound
     * @param id - the sound id
     * @param context - the context
     */
    public void playSound(int id, final Context context) {

        Log.d("Sound", "Play GameSound " + id + 1 + ".");
        soundPool.play(id + 1, this.volume, this.volume, 1, 0, 1f);
        Log.d("Sound", "GameSound " + id + 1 + " Played");
    }
}

答案 1 :(得分:2)

为了支持较旧的API级别,您需要将initializeRecentAPISoundPool()中的代码封装到单独的类中。加载Sound类时,类加载器会检查它引用的所有类是否也存在(它不加载它们,只检查它们是否存在)。在您的情况下,在较旧的API级别上,类AudioAttributes$Builder不存在,因此类加载器无法加载您的Sound类。

解决这个问题的方法是将仅在较新的API级别中支持的代码移动到单独的类中,并且当您知道自己在至少具有该API级别的设备上运行时,仅实例化(或使用)该类

您已经通过检查API级别并调用2种不同的方法来正确执行此操作,具体取决于设备的API级别。要完成这项工作,您只需将代码移到一个单独的类中。

注意:有趣的是,当使用现有类的较新方法时,这不是问题。类加载器在加载类时不会检查您引用的所有方法是否存在。