使用静态侦听器重构代码

时间:2013-02-18 12:19:16

标签: android static refactoring listener

经过一些调试后,我在现有的生产代码中找到了以下内容:

public class SomeTTS {
    private static TTSSpeechListener mSpeechListener;
    private static TTSBreakListener mBreakListener;
    // more static (!!!) listeners
    private String mPath;

    public TTS(String path, TTSSpeechListener speechListener)
            throws RuntimeException {
        // ...
        mSpeechListener = speechListener;
        mBreakListener = null;
        // more listeners set to null
        // ...
    }
    // called from NATIVE code that I cannot change
    private static void onReceiveSpeechData(byte[] samples) {
        mSpeechListener.onSpeechData(samples);
    }
    // ...
}

该类是本机库(Android,NDK,JNI)的包装器。我无权访问本机库源。 (当然,你看到了问题:在我创建SomeTTS的第二个实例后,第一个实例不再起作用了。)我有点震惊:除了一个小学生,我不会想到这样的错误。可能他们正在使用童工。或者,更有可能的是,有人无法向他的经理解释演示和生产代码之间的区别。

无论如何,我必须让它发挥作用。我有一些想法,但我现在提出的建议远非完美。任何想法如何重构它?

1 个答案:

答案 0 :(得分:0)

这就是我所做的:我让课程破碎并将其包装在一个提供合理API的课程中。

由于它是TTS,并且让TTS一次只说出一个请求是合理的,我使用了一个指向当前SomeTTS实例的静态指针,并使调用同步。我无法修复SomeTTS类,但我可以确保我对其方法的调用是正确的 - 这意味着我不会调用某些方法。

public class SomeTTS {
    private TTSSpeechListener mSpeechListener;
    // ... more listeners, NOT static ...

    private static volatile SomeTTS currentTTS;
    protected static Object currentTtsAccessLock = new Object();

    public static TTSSpeechListener currentSpeechListener() {
        synchronized (currentTtsAccessLock) {
            return currentTTS == null ? null : currentTTS.mSpeechListener;
        }
    }
    public static void setCurrentTTS(SomeTTS tts) {
        synchronized (currentTtsAccessLock) {
            currentTTS = tts;
        }
    }

    // called from NATIVE code that I cannot change
    private static void onReceiveSpeechData(byte[] samples) {
        TTSSpeechListener speechListener = currentSpeechListener();
        if (speechListener != null) {
            speechListener.onSpeechData(samples);
        } else  {
            // Just no better idea. But this should never happen.
            Log.e("SomeTTS","ERROR: speechListener == null  samples: "+samples.length);
        }
    }

    // ...
}

这就是全班同学。仍然可以对其方法进行不正确的调用;该学科将使用MyTTSEngine代替。该类MyTTSEngine提供了合理的API; SomeTTS没有。

class MyTTSEngine {
    private SomeTTS mTTS;
    private Object upperLevelTtsLock = new Object();

    // ...

    public void say(String text) {
        // ...
        synchronized (upperLevelTtsLock) {
            TTS.setCurrentTTS(mTTS);
            try {
                mTTS.clearAbortState();
                mTTS.synthesizeFromString(text);
            } finally {
                TTS.setCurrentTTS(null);
            }
        }
        // ...
    }
}