使用所有静态字段/方法的类是否合适?

时间:2018-08-01 19:16:37

标签: java android

我正在Android Studio中编写一个应用程序,几乎每个活动都会以一种或另一种方式播放1-3秒的声音。活动将包含方形图像,触摸时会发出声音。

我在所有活动中一遍又一遍地编写了用于媒体播放的代码,因此我认为可以制作一个单独的类来处理播放。另外,我在不同活动的声音互相播放时遇到问题:

public class SoundPlayback {

/** provides access to volume and ringer mode control. */
private static AudioManager audioManager;

/** Handles playback of all the sound files */
// Initialize the MediaPlayer as a global variable
private static MediaPlayer mediaPlayer;

/**
 * The listener gets triggered when the mediaPlayer has completed
 * playing the audio file.
 */
private static MediaPlayer.OnCompletionListener completionListener = new MediaPlayer.OnCompletionListener() {
    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
        releaseMediaPlayer();
    }
};

/**
 * This listener gets triggered whenever the audio focus changes
 * (i.e., we gain or lose audio focus because of another app or device).
 */
private static AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
    @Override
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT ||
                focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
            // The AUDIOFOCUS_LOSS_TRANSIENT case means that we've lost audio focus for a
            // short amount of time. The AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK case means that
            // our app is allowed to continue playing sound but at a lower volume. We'll treat
            // both cases the same way because our app is playing short sound files.

            // Pause playback and reset player to the start of the file. That way, we can
            // play the word from the beginning when we resume playback.
            mediaPlayer.pause();
            mediaPlayer.seekTo(0);
        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
            // The AUDIOFOCUS_LOSS case means we've lost audio focus
            // Stop playback and clean up resources
            releaseMediaPlayer();
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // The AUDIOFOCUS_GAIN case means we have regained focus and can resume playback.
            mediaPlayer.start();
        }
    }
};

public static void initializeManagerService(Context context) {
    // Create and setup the Audio Manager to request audio focus
    audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}

public static void initializePlayer(Context context, int audioResourceID) {
    // Request audio focus in order to play the audio file. The app needs to play a
    // short audio file, so we will request audio focus with a short amount of time
    // with AUDIOFOCUS_GAIN_TRANSIENT.
    int result =  audioManager.requestAudioFocus(audioFocusChangeListener,
            AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

    if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        // Using the factory method create() we set the audio resource to be played when
        // chosen category is selected.
        mediaPlayer = MediaPlayer.create(context, audioResourceID);

        // Stat playback of audio
        mediaPlayer.start();

        // Listen for when the playback has finished
        mediaPlayer.setOnCompletionListener(completionListener);

    }
}

/** Clean up the media player by releasing its resources */
public static void releaseMediaPlayer() {
    // If the media player is not null, then it may be currently playing a sound.
    if (mediaPlayer != null) {
        // Regardless of the current state of the media player, release its resources
        // because we no longer need it.
        mediaPlayer.release();

        // Set the media player back to null. For our code, we've decided that
        // setting the media player to null is an easy way to tell that the media player
        // is not configured to play an audio file at the moment.
        mediaPlayer = null;

        // Regardless of whether or not we were granted audio focus, abandon it. This also
        // unregisters the AudioFocusChangeListener so we don't get anymore callbacks.
        audioManager.abandonAudioFocus(audioFocusChangeListener);
    }
}

}

并在活动的onCreate方法中这样调用:

    // Store context to be used for calling SoundPlayback
    final Context context = getApplicationContext();

    // Initialize the Audio Manager AUDIO_SERVICE
    SoundPlayback.initializeManagerService(context);

    // Set onItemClickListener to handle opening of categories
    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View v,
                                int position, long id) {
            // Store the current Category object that the CategoryAdapter is iterating, using
            // the ArrayList method get(). Input parameter is int index, which corresponds
            // to the given position the user clicked on.
            Category currentCategory = categories.get(position);

            // Release the media player if it currently exists, because we are about to
            // play a different sound file.
            SoundPlayback.releaseMediaPlayer();

            // Initialize playback of the sound related to the item the user has selected
            SoundPlayback.initializePlayer(context, currentCategory.getAudioResourceID());

    });

此解决方案非常适合我的应用程序,但感觉就像我在作弊。使用仅包含静态字段和方法的类是正确的情况吗?我应该改用单例吗?

我不理会服务,因为播放的声音只有几秒钟长,而且感觉不需要所需的内存/电池使用量。

1 个答案:

答案 0 :(得分:1)

有可能,但单例总是更好的解决方案。除非您必须使用全静态解决方案,否则很难理解这一点,因此请尝试一下,然后看它对您的影响。

例如,您如何为此编写单元测试?

再举一个例子-假设您有一个Notification界面并且有许多实现...声音通知程序,阴影通知程序,手表通知程序,电子邮件通知程序... ...您如何调整静态实现并使用它在带有其他“通知”对象的集合中?并不是您现在想要的,只是使用所有静态方法非常不灵活,使得解决许多问题的解决方案涉及傻适配器和复制/粘贴解决方案。

顺便说一句,单例也不是一个好主意,但是如果您不使用DI,它可能是您可以使用的最佳简便选择。