我遇到了奇怪的行为,NullPointerException
(有时候)在Singleton
中使用了Activity
模式。
清单中的活动(声明了方向格局):
<activity
android:name="com.lux.game.MainActivity"
android:screenOrientation="landscape" />
活动类:
private GameManager.OnEventListener mEventListener = new GameManager.OnEventListener {
@Override
public void onEvent(Event event) {
if (event == Event.PLAYER_SELECTED_PUZZLE) {
// Do something on the UI
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
// If the orientation is landscape, then initialize the Game Manager
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
GameManager.getInstance().init();
// Register an interface to deal with game events
GameManager.getInstance().registerForEvent(mEventListener);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// The activity was destroyed, remove the interface and clear the references
GameManager.getInstance().cleanUp();
}
GameManager
单身人士:
public class GameManager {
private static GameManager mInstance;
private GameManager() {
}
public static synchronized getInstance() {
if (mInstance == null) {
mInstance = new GameManager();
}
return mInstance;
}
}
正如你所看到的,我正在使用GameManager
单身来处理游戏事件(玩家选择一张牌,游戏结束等)。如果方向是横向的并且onCreate()
被传递给单例并且它被存储为类的成员,则单例在interface
处被实例化。活动interface
已删除onDestroy()
。
活动生命周期和日志:
#1 onCreate(), orientation: LANDSCAPE
#2 back button pressed
#3 onDestroy(), orientation: PORTRAIT
一切都按预期工作,直到我开始通过锁定/解锁测试应用程序并按下设备上的 HOME 按钮(真实设备,而不是模拟器)
活动生命周期和日志:
#1 onCreate(), orientation: LANDSCAPE
#2 lock phone
#3 onDestroy(), orientation: PORTRAIT
#4 onCreate(), orientation: PORTRAIT
#5 unlock phone
#6 onDestroy(), orientation: PORTRAIT
#7 onCreate(), orientation: LANDSCAPE
onCreate
和onDestroy
被称为服务器时间(正常行为,因为方向更改),但这不会产生问题,因为活动的lifecycle
方法在中被调用已删除1>},并且interface
已删除,我不会留下任何可能导致内存泄漏的引用。
如果以不同的顺序调用上述步骤,问题(有时)会浮出水面:
#1 onCreate(), orientation: LANDSCAPE (inst #1)
#2 lock phone
#3 onDestroy(), orientation: PORTRAIT (inst #1)
#4 onCreate(), orientation: PORTRAIT (inst #2)
#5 unlock phone
#6 onCreate(), orientation: LANDSCAPE (inst #3)
#7 onDestroy(), orientation: PORTRAIT (inst #2)
如您所见,与前面的步骤相比,步骤 6 和 7 是反向的。在onCreate
之前调用onDestroy
。我还添加了一个数字(inst #N),它表示创建了多少个活动实例,哪些活动实例被销毁。
根据日志,当我锁定/解锁手机时,总共创建了3个不同的活动实例。问题是由最后一步引起的,当第三个活动(inst#3)被创建,第二个活动(inst#2)被破坏时。我正在使用Singleton
(整个应用程序中只存在1个实例)来处理事件和管理游戏,活动的onDestroy
Singleton
期望游戏结束,并且它必须删除对活动的引用。这样,如果游戏中发生了事件,则NullPointerException
被抛出,因为Singleton
已清除所有引用。
答案 0 :(得分:1)
我认为你应该创建一个新的类来扩展Application并在它们的onCreate()元文件中启动你的Singleton。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
GameManager.getInstance().init();
}
}
在您的清单中,在应用标记中添加 android:name =&#34; MyApplication&#34; 在任何有更好的单例线程安全的情况下,由于你的构造函数,我建议你在应用程序中创建一个静态的isjet。
public class MyApplication extends Application {
public static GameManager gameManager = new GameManager();
@Override
public void onCreate() {
super.onCreate();
gameManager.init();
}
}
然后你可以通过
打电话给你的单身人士MyApplication.gameManager
这是使单例线程安全的最佳方法