我正在尝试创建一个负责播放游戏声音的单例类。我使用方法GameSounds
创建了一个单例类playSound()
。在res文件夹中,我有一个带有文件letter_found.mp3
的子文件夹'raw'。
这是我编写的GameSounds
类的源代码:
import android.app.Application;
import android.content.Context;
import android.media.MediaPlayer;
public class GameSounds extends Application {
private static GameSounds gameSounds = new GameSounds();
private static MediaPlayer soundPlayer;
private static Context mContext;
private static int mySoundId = R.raw.letter_found;
private GameSounds() {
mContext = this;
}
public static GameSounds getInstance() {
return gameSounds;
}
public static void playSound() {
soundPlayer = MediaPlayer.create(mContext, mySoundId);
soundPlayer.start();
}
}
这似乎不起作用,因为我收到以下错误消息:
“ java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法'android.content.res.Resources android.content.Context.getResources()'”
我不明白为什么会这样。我试图搜索Stackoverflow,但找不到解决方案。
非常感谢您的帮助/解释。
答案 0 :(得分:0)
除非您尝试使用Singleton模式,否则不应该继承Application
类。因为Application是基类,所以包含所有其他组件,例如活动和服务。
相反,GameSound类应包含Context
对象和适当的构造函数。
示例)
public class GameSounds {
private GameSounds gameSounds;
private MediaPlayer soundPlayer;
private WeakReference<Context> mContext;
private int mySoundId = R.raw.letter_found;
private GameSounds(Context context) {
mContext = new WeakReference<>(context);
}
public GameSounds getInstance(Context context) {
if (gameSounds == null) {
gameSounds = new GameSounds(context);
}
return gameSounds;
}
public void playSound() {
soundPlayer = MediaPlayer.create(mContext.get(), mySoundId);
soundPlayer.start();
}
}
在此代码中,有WeakReference<Context>
而不是上下文。 WeakReference用于防止内存泄漏,因为如果活动之外有一个实例,则会发生内存泄漏。
要播放声音,请执行GameSounds.getInstance(this).playSound();
。
如果尝试播放声音时Context无法提供,则可以实现initialize
方法,并可以在Application类中调用。
public class GameSounds {
private static GameSounds gameSounds;
private MediaPlayer soundPlayer;
private WeakReference<Context> mContext;
private int mySoundId = R.raw.letter_found;
private GameSounds(Application context) {
mContext = new WeakReference<>(context);
}
public static void initialize(Application context) {
if (gameSounds == null) {
gameSounds = new GameSounds(context);
}
}
public static GameSounds getInstance() {
if (gameSounds == null) {
throw new NullPointerException("You need to initialize this code by GameSound.initialize(this) in application class");
}
return gameSounds;
}
public void playSound() {
soundPlayer = MediaPlayer.create(mContext.get(), mySoundId);
soundPlayer.start();
}
}
在这种情况下,您应该制作this并通过Application类中的GameSound.initialize(this)
初始化GameSound类。
要播放声音,可以使用GameSound.getInstance().playSound()
。
答案 1 :(得分:0)
您可以让一个Singleton持有一个应用程序Context
(NOT Activity上下文),但是实际上您必须在使用Singleton之前设置此上下文,而Singleton可以通过抛出异常来强制实施。请参见下面的示例代码。
public class GameSounds {
private static Context sContext;
public static void setContext(Context context) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null!");
}
// In order to avoid memory leak, you should use application context rather than the `activiy`
context = context.getApplicationContext();
if (context == null) {
throw new IllegalArgumentException("context cannot be null!");
}
sContext = context;
}
private static Context getContext() {
if (sContext != null) {
return (Context)sContext;
}
throw new IllegalStateException("sContext was not set yet! Please call method setContext(Context context) first.");
}
// the rest of other methods. e.g. playSounds()
private static GameSounds gameSounds = new GameSounds();
private GameSounds() {
}
public static GameSounds getInstance() {
return gameSounds;
}
public void playSound() {
Context context = getContext();
soundPlayer = MediaPlayer.create(context, mySoundId);
soundPlayer.start();
}
}