玩家死亡后启动EndingScreen Activity导致应用崩溃的问题排查求助
玩家死亡后启动EndingScreen Activity导致应用崩溃的问题排查求助
嘿,刚入门就敢做游戏项目,给你点个赞!不过遇到这个跳转崩溃的问题确实闹心,我先从你给的LogCat和代码里找找问题根源,再给你具体的解决步骤~
先看崩溃的核心原因
从你贴的LogCat里能看到关键错误:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
而且崩溃发生在Thread-2,也就是你的游戏循环子线程里。这说明两个问题:
- 你在**非UI线程(游戏子线程)**里尝试启动Activity,这违反了Android的规则——所有UI相关操作(包括启动Activity)必须在主线程执行。
- 你用的
getContext()在子线程里返回了null,导致创建Intent时找不到有效的上下文。
再看你代码里的问题点
你在draw方法里处理玩家死亡跳转的逻辑,而draw是被游戏循环的子线程调用的,这本身就不符合Android的UI操作规范。另外getContext()在子线程环境下可能因为线程绑定问题取不到有效的上下文,直接导致NullPointerException。
具体解决办法
我给你一步步改代码:
1. 给Game类保留有效的Activity引用
在Game类里添加一个Activity成员变量,构造的时候传入MainActivity的实例,避免依赖可能为空的getContext():
private Activity mGameActivity; // 修改你的Game类构造方法,传入Activity实例 public Game(Activity activity, ...) { mGameActivity = activity; // 其他初始化代码... }
注意:在MainActivity里创建Game实例的时候,要传this进去,比如new Game(this, ...)。
2. 把跳转逻辑移到Update方法,并且切换到主线程执行
玩家死亡的判断逻辑应该放在update方法里(负责逻辑更新),而不是draw方法(只负责绘制),然后用runOnUiThread把跳转操作切到主线程:
public void update() { // 先判断玩家是否死亡 if (player.getHealthPoints() <= 0) { // 加个playerDead判断,避免重复触发跳转 if (!playerDead) { playerDead = true; // 切换到主线程执行跳转操作 mGameActivity.runOnUiThread(new Runnable() { @Override public void run() { // 创建Intent,用有效的Activity上下文 Intent intent = new Intent(mGameActivity, EndScreen.class); intent.putExtra("score", gameLoop.getCurrentKillCount()); mGameActivity.startActivity(intent); // 停止游戏循环,避免后续还在更新逻辑 gameLoop.stopLoop(); } }); } return; } // 下面是原来的更新逻辑... joystick.update(); player.update(); // ...其余代码保持不变 }
3. 清理Draw方法里的跳转逻辑
把draw方法里的跳转相关代码删掉,让它只负责绘制:
@Override public void draw(Canvas canvas) { super.draw(canvas); // 绘制所有游戏元素的代码... tilemap.draw(canvas, gameDisplay); player.draw(canvas, gameDisplay); // ...其余绘制代码保持不变 // 只保留绘制游戏结束相关的UI(如果有的话) if (playerDead) { // 比如绘制游戏结束的文字或图片,不要在这里处理跳转 // gameOver.draw(canvas); } }
4. 最后检查AndroidManifest.xml
确保EndScreen已经在Manifest里注册了,这是很容易忘的点:
<application ...> <!-- 你的其他Activity --> <activity android:name=".EndScreen"/> </application>
为什么这样改能解决问题?
- 用Activity实例作为上下文,避免了
getContext()返回null的情况 - 用
runOnUiThread把启动Activity的操作放到主线程,符合Android的UI操作规则 - 把逻辑判断和绘制职责分开,代码结构更清晰,也避免了子线程操作UI的问题
按照这个步骤改完,应该就能正常跳转到结束界面啦,祝你项目顺利完成!
备注:内容来源于stack exchange,提问作者Benny Stein - Scinto
相关产品推荐
相关产品推荐

