Получение необработанного ресурса (звука) в неактивном классе - PullRequest
0 голосов
/ 27 февраля 2019

Я пытаюсь создать синглтон-класс, который будет отвечать за воспроизведение игровых звуков.Я создал одноэлементный класс GameSounds с методом playSound().В папке res у меня есть подпапка 'raw' с файлом letter_found.mp3.

Это исходный код класса 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 голосов
/ 27 февраля 2019

У вас может быть приложение Singleton, содержащее приложение Context (НЕ контекст деятельности), но на практике вам нужно установить этот контекст, прежде чем использовать ваш синглтон, который можно принудительно вызвать, создавая исключения.Смотрите ниже пример кода.

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();
    }
}
0 голосов
/ 27 февраля 2019

Вы не должны наследовать Application класс , если только вы не попытаетесь использовать шаблон Singleton.Поскольку 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 и вызванные в классе приложения.

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

В этом случае вы должны сделать Класс приложения и инициализировать класс GameSound с помощью GameSound.initialize(this) в классе приложения.

Для воспроизведения звука GameSound.getInstance().playSound() хорошо.

...