在非活动类中获取原始资源(声音)

时间:2019-02-27 01:12:54

标签: java android singleton android-resources

我正在尝试创建一个负责播放游戏声音的单例类。我使用方法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,但找不到解决方案。

非常感谢您的帮助/解释。

2 个答案:

答案 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();
    }
}