我使用这个标准的 SoundManager。它在我所有的设备上都能正常工作,但只是偶尔在市场上出现这些错误
SoundManager.playSound(SoundManager.java:87) 中的 NullPointerException
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;
}
}
这是启动 Activity 中的清理调用:
//REMOVE SOUND MEMORY ALLOCATION
@Override
public void onDestroy()
{
super.onDestroy();
SoundManager.cleanup();
}
有谁知道是什么原因导致这些偶尔出现的罕见错误以及如何预防这些错误?这发生在我所有使用此 SoundManager 的应用程序中......即使是有点奇怪的猜测也会有所帮助。
最佳答案
当您初始化 SoundManager 时,请使用 Application Context。您可能在 Activity 之间移动时遇到问题。如果 SoundManager 比您的 Activity 生命周期更长。您甚至可以在您的应用程序中进行初始化。
public class MyAndroidApp extends Application {
@Override
public void onCreate() {
super.onCreate();
SoundManager.initSounds(this);
}
}
我也同意 WarrenFaith 的观点。唯一的静态变量应该是 _instance 和 getInstance()。
此外,如果您在 Application 类中加载声音,则无需担心同步问题。
如果对您有帮助,您可以查看我使用的代码。它利用来自 http://code.google.com/p/opensl-soundpool/ 的 OpenSL SoundPool 库
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() ;
}
}
仍在进行中,但已完成工作。
关于android - SoundManager 中偶尔出现 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11917595/
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm
下面的代码工作正常:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson)do|key,oldv,newv|ifkey==:aoldvelsifkey==:bnewvelsekeyendendputskerson.inspect但是如果我在“ifblock”中添加return,我会得到一个错误:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson
我正在使用macos,我想使用ruby驱动程序连接到sqlserver。我想使用tiny_tds,但它给出了缺少free_tds的错误,但它已经安装了。怎么能过这个?~brewinstallfreetdsWarning:freetds-0.91.112alreadyinstalled~sudogeminstalltiny_tdsBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtiny_tds:ERROR:Failedtobuildgemnativeextension.完整日志如下:/System
我有以下haml:9%strongAskedby:10=link_to@user.full_name,user_path(@user)11.small="(#{@question.created_at.strftime("%B%d,%Y")})"这当前将链接和日期放在不同的行上,当它看起来像“链接(日期)”并且日期的类跨度为小...... 最佳答案 您的代码将生成类似这样的html:Askedby:UsernameApril26,2011当您使用类似.small的东西(即使用点而不指定元素类型)时,haml会创建一个implicit
下面有没有更优雅的方法来实现这个:输入:array=[1,1,1,0,0,1,1,1,1,0]输出:4我的算法:streak=0max_streak=0arr.eachdo|n|ifn==1streak+=1elsemax_streak=streakifstreak>max_streakstreak=0endendputsmax_streak 最佳答案 类似于w0lf'sanswer,但通过从chunk返回nil来跳过元素:array.chunk{|x|x==1||nil}.map{|_,x|x.size}.max
有没有一种有效的方法来做到这一点。我有一个数组a=[1,2,2,3,1,2]我想按升序输出出现的频率。示例[[3,1],[1,2],[2,3]]这是我的ruby代码。b=a.group_by{|x|x}out={}b.eachdo|k,v|out[k]=v.sizeendout.sort_by{|k,v|v} 最佳答案 a=[1,2,2,3,1,2]a.each_with_object(Hash.new(0)){|m,h|h[m]+=1}.sort_by{|k,v|v}#=>[[3,1],[1,2],[2,3]]
我认为我对线程在ruby中的工作原理存在根本性的误解,我希望获得一些见解。我想要一个简单的生产者和消费者。首先,生产者线程从文件中提取行并将它们粘贴到SizedQueue中;当那些用完时,在末端贴上一些token,让消费者知道事情已经完成。require'thread'numthreads=2filename='edition-2009-09-11.txt'bq=SizedQueue.new(4)producerthread=Thread.new(bq)do|queue|File.open(filename)do|f|f.eachdo|r|queue现在有几个消费者。为简单起见,让
我最近开始了一个项目,团队决定我们希望使用jQuery而不是Prototype/Scriptaculous来满足我们的javascript需求。我们设置了我们的项目,并开始切换。插件已安装viatheseinstructions,一切都按计划进行。不久之后,当尝试运行“./script/server”时,我们收到以下错误:=>Rails2.3.2applicationstartingonhttp://0.0.0.0:3000/usr/local/lib/ruby/gems/1.9.1/gems/activesupport-2.3.2/lib/active_support/depende
这个错误已经有好几个月了,在这里:http://www.ruby-forum.com/topic/1094002其中显示代码更改的两个链接:https://github.com/godfat/ruby/commit/f4e0e8f781b05c767ad2472a43a4ed0727a75708https://github.com/godfat/ruby/commit/c7a6cf975d88828c2ed27d253f41c480f9b66ad6我有Ruby1.9.2和rvm。我会把这些更改粘贴到适当的文件中,但我不知道如何粘贴。这在几天前就奏效了。我不能像这样执行RubyonRai