Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/195.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android SoundManager中偶尔出现NullPointerException_Android - Fatal编程技术网

Android SoundManager中偶尔出现NullPointerException

Android SoundManager中偶尔出现NullPointerException,android,Android,我使用这个标准的SoundManager。它在我所有的设备上都能正常工作,但只是在市场上偶尔出现这些错误 SoundManager.playSound中的NullPointerException(SoundManager.java:87) SoundManager.cleanup(SoundManager.java:107)中的NullPointerException 代码如下: public class SoundManager { private static SoundManag

我使用这个标准的SoundManager。它在我所有的设备上都能正常工作,但只是在市场上偶尔出现这些错误

  • SoundManager.playSound中的NullPointerException(SoundManager.java:87)

  • SoundManager.cleanup(SoundManager.java:107)中的NullPointerException

  • 代码如下:

    public class SoundManager {
    
        private static SoundManager _instance;
        private static SoundPool mSoundPool; 
        private static HashMap<Integer, Integer> mSoundPoolMap; 
        private static AudioManager  mAudioManager;
        private static Context mContext;
    
        private SoundManager(){   }
    
        static synchronized public SoundManager getInstance(){
            if (_instance == null) 
              _instance = new SoundManager();
            return _instance;
         }
    
    
        public static  void initSounds(Context theContext){ 
             mContext = theContext;
             mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
             mSoundPoolMap = new HashMap<Integer, Integer>(); 
             mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);        
        } 
    
    
        public static void addSound(int Index,int SoundID){
            mSoundPoolMap.put(Index, mSoundPool.load(mContext, SoundID, 1));
        }
    
    
        public static void loadSounds(){
    
            mSoundPoolMap.put(1, mSoundPool.load(mContext, R.raw.kick1, 1)); 
            mSoundPoolMap.put(2, mSoundPool.load(mContext, R.raw.kick2, 1)); 
            mSoundPoolMap.put(3, mSoundPool.load(mContext, R.raw.kick3, 1));    
    
    
        }
    
    
        public static void playSound(int index, float volume){      
                 **line 87:** float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
                 streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
                 mSoundPool.play(mSoundPoolMap.get(index), streamVolume*volume, streamVolume*volume, 1, 0, 1); 
        }
    
    
        public static void stopSound(int index){
            mSoundPool.stop(mSoundPoolMap.get(index));
        }
    
        public static void cleanup(){
            **line 107:** mSoundPool.release();
            mSoundPool = null;
            mSoundPoolMap.clear();
            mAudioManager.unloadSoundEffects();
            _instance = null;
    
        }
    }
    

    有人知道是什么导致了这些偶尔出现的罕见错误,以及如何预防它们吗?这发生在我所有使用此SoundManager的应用程序中。。。即使是一点od推测也会有所帮助。

    有点混乱。您不(也不应该)对静态方法和变量使用单例模式(getInstance()和minInstance变量除外)。这没有道理

    您应该摆脱静态,并将该类完全作为一个单例使用,以确保没有任何变量可能因为并发问题而为null(我猜您的null问题是并发的结果)

    以下是我将使用的类:

    public class SoundManager {
        // syncronized creation of mInstance
        private final static SoundManager mInstance = new SoundManager(); 
        private SoundPool mSoundPool; 
        private HashMap<Integer, Integer> mSoundPoolMap; 
        private AudioManager  mAudioManager;
        private Context mContext;
    
        private SoundManager() {}
    
        public static SoundManager getInstance() {
            return _instance;
        }
    
        public void initSounds(Context theContext) { 
            mContext = theContext;
            mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
            mSoundPoolMap = new HashMap<Integer, Integer>(); 
            mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);        
        } 
    
        public void addSound(int Index,int SoundID){
            mSoundPoolMap.put(Index, mSoundPool.load(mContext, SoundID, 1));
        }
    
        public void loadSounds() {
            mSoundPoolMap.put(1, mSoundPool.load(mContext, R.raw.kick1, 1)); 
            mSoundPoolMap.put(2, mSoundPool.load(mContext, R.raw.kick2, 1)); 
            mSoundPoolMap.put(3, mSoundPool.load(mContext, R.raw.kick3, 1));
        }
    
        public void playSound(int index, float volume){      
            float streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
            streamVolume = streamVolume / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
            mSoundPool.play(mSoundPoolMap.get(index), streamVolume*volume, streamVolume*volume, 1, 0, 1); 
        }
    
        public void stopSound(int index) {
            mSoundPool.stop(mSoundPoolMap.get(index));
        }
    
        // I wouldn't use this until I am extremely sure that I
        // will never ever use the SoundManager again... so
        // probably never. Let the SoundManager die when the application dies...
        public void cleanup() {
            mSoundPool.release();
            mSoundPool = null;
            mSoundPoolMap.clear();
            mAudioManager.unloadSoundEffects();
        }
    }
    
    然后,在需要使用该类的任何地方:

    SoundManager.getInstance().playSound(index, volume);
    // or what ever you need
    
    更新:

    要回答您的评论:

    如果您在Application::onCreate()中创建实例,那么您将始终拥有该实例,并且该实例也是内部变量。当用户离开应用程序时,可能会发生两种情况:

  • 它可以被销毁,但一旦用户再次进入应用程序,onCreate就会被再次调用
  • 什么都没有发生,实例仍然存在
  • 因此,在这两种情况下,您永远不会丢失实例


    仅仅因为其他人可能会以特定的方式执行此操作,并不意味着此方法是正确的。

    当您初始化SoundManager时,请使用应用程序上下文。您可能会在活动之间移动问题。如果SoundManager比您的活动寿命长。您甚至可以在应用程序中初始化

    public class MyAndroidApp extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            SoundManager.initSounds(this);
        }
    }
    
    我也同意沃伦信仰。唯一的静态应该是_instance和getInstance()

    此外,如果在应用程序类中加载声音,则无需担心同步问题

    如果有帮助的话,你可以看看我使用的代码。它利用了

    import java.util.ArrayList;
    导入java.util.HashMap;
    导入java.util.Random;
    导入java.util.concurrent.AtomicBoolean;
    导入android.content.Context;
    导入android.media.AudioManager;
    导入android.media.MediaPlayer;
    导入com.kytomaki.openslsoundpool.JavaSoundPool;
    导入com.kytomaki.openslsoundpool.openslsoundpool;
    导入com.kytomaki.openslsoundpool.SoundPoolIf;
    最终公共类SoundManager
    {
    //预定的声音ID
    公共静态最终整数无音=-1;
    公共静态最终整数获胜者=-2;
    //日志记录标签
    受保护的静态最终字符串标记=“SoundManager”;
    /**用于加载和播放声音**/
    私人语境;
    /**声音可以从单独的线程禁用**/
    私人最终原子声;
    //声音阵列
    私人最终ArrayList winningSounds;
    私人最终声音池IF声音池;
    私有最终HashMap soundPoolMap;
    私人最终音频经理AudioManager;
    /**用于声音播放的单例对象**/
    私有静态SoundManager soundManagerInstance;
    私有静态最终int使用_SOUNDPOOL=1;
    私有静态最终整数使用_OPENSL=2;
    私有静态int use=use_SOUNDPOOL;
    /**
    *创建新SoundManager的专用方法
    *这是一个单例对象 *@param context应该是应用程序上下文 */ 专用SoundManager(最终上下文) { setContext(context); useSound=新原子布尔值(true); audioManager=(audioManager)context.getSystemService(context.AUDIO\u服务); soundPoolMap=新HashMap(); winningSounds=新的ArrayList(); if(use==use_OPENSL) { soundPool=新的OpenSLSoundPool(2,OpenSLSoundPool.RATE_44_1,OpenSLSoundPool.FORMAT_16,1); }否则{ soundPool=新的JavaSoundPool(2); } } /** *必须在使用前调用
    *最好在应用程序类中初始化 *@param上下文 */ 公共静态void initSoundManager(最终上下文) { 如果(soundManagerInstance==null) { soundManagerInstance=新的SoundManager(上下文); } 其他的 { 抛出新的UnsupportedOperationException(“已创建声音管理器”); } } /** *重载方法以允许使用OpenSL *@param上下文 *@param useonsl */ 公共静态void initSoundManager(最终上下文上下文,最终布尔值useOpenSL){ 如果(使用OpenSL){ 使用=使用OPENSL; } initSoundManager(上下文); } /** *必须首先用{@link SoundManager#initSoundManager(Context)}初始化 *@SoundManager的返回实例 */ 公共静态SoundManager getSoundManagerInstance() { if(soundManagerInstance!=null) { 返回音质; } 其他的 { 抛出新的UnsupportedOperationException(“SoundManager必须初始化”); } } /** *从android资源文件R.id.sound添加声音
    *使用SoundManager.play(soundId)播放 *@param soundId *@param soundResourceId */ public void addSound(最终int-soundId,最终int-soundResourceId) { soundPoolMap.put(soundId,soundPool.load(getContext(),soundResourceId)); } /** *从要随机播放的资源中添加获胜的声音
    *由SoundManager调用。播放(赢家) *@param soundResourceId */ 聚氨基甲酸酯
    SoundManager.getInstance().playSound(index, volume);
    // or what ever you need
    
    public class MyAndroidApp extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            SoundManager.initSounds(this);
        }
    }
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Random;
    import java.util.concurrent.atomic.AtomicBoolean;
    
    import android.content.Context;
    import android.media.AudioManager;
    import android.media.MediaPlayer;
    
    import com.kytomaki.openslsoundpool.JavaSoundPool;
    import com.kytomaki.openslsoundpool.OpenSLSoundPool;
    import com.kytomaki.openslsoundpool.SoundPoolIf;
    
    final public class SoundManager
    {
        // Predetermined sound ID's
        public static final int             NO_SOUND        = -1 ;
        public static final int             WINNER          = -2 ;
    
        // Tag for logging
        protected static final String       TAG             = "SoundManager" ;
    
        /** Used to load and play sounds **/
        private Context                     context ;
    
        /** Sound can be disable from separate thread **/
        private final AtomicBoolean         useSound ;
    
        // Sound Arrays
        private final ArrayList<Integer>    winningSounds ;
        private final SoundPoolIf           soundPool ;
        private final HashMap<Integer, Integer> soundPoolMap ;
        private final AudioManager          audioManager ;
    
        /** Singleton object for sound play back **/
        private static SoundManager         soundManagerInstance ;
    
    
        private static final int            USE_SOUNDPOOL   = 1 ;
        private static final int            USE_OPENSL      = 2 ;
        private static int                  use             = USE_SOUNDPOOL ;
    
    
    
        /**
         * Private Method to create a new SoundManager<br>
         * This is a Singleton Object
         * @param context Should be the Application Context
         */
        private SoundManager( final Context context )
        {
            setContext( context ) ;
            useSound = new AtomicBoolean( true ) ;
            audioManager = (AudioManager) context.getSystemService( Context.AUDIO_SERVICE ) ;
    
            soundPoolMap = new HashMap<Integer, Integer>() ;
            winningSounds = new ArrayList<Integer>() ;
    
            if ( use == USE_OPENSL )
            {
                soundPool = new OpenSLSoundPool( 2, OpenSLSoundPool.RATE_44_1, OpenSLSoundPool.FORMAT_16, 1) ;
            } else {
                soundPool = new JavaSoundPool( 2 ) ;
            }
        }
    
        /**
         * Must be called before using<br>
         * Best to initialize in Application Class
         * @param context
         */
        public static void initSoundManager( final Context context )
        {
            if ( soundManagerInstance == null )
            {
                soundManagerInstance = new SoundManager( context ) ;
            }
            else
            {
                throw new UnsupportedOperationException( "Sound manager has already been created" ) ;
            }
        }
    
        /**
         * Overloaded method to allow use of OpenSL
         * @param context
         * @param useOpenSL
         */
        public static void initSoundManager( final Context context, final boolean useOpenSL){
            if(useOpenSL){
                use = USE_OPENSL;
            }
            initSoundManager(context);
        }
    
        /**
         * Must initialize first with {@link SoundManager#initSoundManager(Context)}
         * @return instance of SoundManager
         */
        public static SoundManager getSoundManagerInstance()
        {
            if ( soundManagerInstance != null )
            {
                return soundManagerInstance ;
            }
            else
            {
                throw new UnsupportedOperationException( "SoundManager must be initalized" ) ;
            }
        }
    
    
        /**
         * Add a sound from an android resource file R.id.sound<br>
         * To be played back with SoundManager.play(soundId)
         * @param soundId
         * @param soundResourceId
         */
        public void addSound( final int soundId, final int soundResourceId )
        {
            soundPoolMap.put(soundId, soundPool.load(getContext(), soundResourceId));
        }
    
        /**
         * Adds a winning sound from a resource to be played at random<br>
         * Called by SoundManager.play(WINNER)
         * @param soundResourceId
         */
        public void addWinningSound( final int soundResourceId )
        {
            winningSounds.add( soundResourceId ) ;
        }
    
        /**
         * Plays a sound first checking if sound is enabled
         * @param soundToPlay soundId or WINNER to play random winning sound
         */
        public synchronized void play( final int soundToPlay )
        {
            if ( isUseSound() )
            {
                switch ( soundToPlay )
                {
                    case NO_SOUND :
                        break ;
                    case WINNER :
                        // Play a random winning sound using media player
                        final MediaPlayer mp ;
                        mp = MediaPlayer.create( getContext(), randomWinnerSound() ) ; 
                        if ( mp != null )
                        {
                            mp.seekTo( 0 ) ;
                            mp.start() ;
                        }
                        break ;
                    default :
                        playSound( soundToPlay ) ;
                        break ;
                }
            }
        }
    
        /**
         * Calls soundpool.play
         * @param soundToPlay
         */
        private void playSound( final int soundToPlay )
        {
            float streamVolume = audioManager.getStreamVolume( AudioManager.STREAM_MUSIC ) ;
            streamVolume = streamVolume / audioManager.getStreamMaxVolume( AudioManager.STREAM_MUSIC ) ;
            soundPool.play(soundPoolMap.get(soundToPlay), streamVolume);
        }
    
        /**
         * @return random winning sound position
         */
        private int randomWinnerSound()
        {
            final Random rand = new Random() ;
            final int playNumber = rand.nextInt( winningSounds.size() ) ;
            return winningSounds.get( playNumber ) ;
        }
    
        /**
         * @param context the context to set
         */
        private final void setContext( final Context context )
        {
            this.context = context ;
        }
    
        /**
         * @return the context
         */
        private final Context getContext()
        {
            return context ;
        }
    
        /**
         * @param useSound false to disable sound
         */
        public final void setUseSound( final boolean useSound )
        {
            this.useSound.set( useSound ) ;
        }
    
        /**
         * @return the useSound
         */
        public boolean isUseSound()
        {
            return useSound.get() ;
        }
    
    
    }