Android Studio中Java非Activity类(SurfaceView)实现页面切换问题
Hey there! Let's break down why your level-switching code works in the menu Activity but not in your Game class, and fix it step by step.
The core issue here is that your Game class extends SurfaceView—a UI component, not an Activity. Your main menu works because it's an Activity, which has direct access to the Android context and the ability to launch other components out of the box. SurfaceViews don't have that same capability, so we need to adjust how you handle the level switch.
Step 1: Make sure your Game class holds a valid Activity Context
First, you need to store a reference to the Activity context that's hosting your Game SurfaceView. Add this to your Game class:
public class Game extends SurfaceView implements SurfaceHolder.Callback { private Context mActivityContext; // Constructor public Game(Context context) { super(context); // Save the context—make sure you pass the hosting Activity's context here, not Application context! mActivityContext = context; // Rest of your initialization code... } }
Important: Never use Application Context to launch Activities—it doesn't have a task stack and will throw an exception. Always pass the Activity that's displaying your Game view.
Step 2: Fix the Activity launch code in your Game class
Your menu's working code probably looks something like this:
startActivity(new Intent(MainMenuActivity.this, NextLevelActivity.class));
But in the Game class, you can't use Game.this (it's not an Activity). Instead, cast your saved context to an Activity and launch the level from there. Also, if your game logic runs on a background thread (common in SurfaceView games), you need to run the launch code on the main UI thread:
// Inside your Game class, when the player hits the target score: if (playerScore >= targetScore) { if (mActivityContext instanceof Activity) { // Switch back to main thread if needed ((Activity) mActivityContext).runOnUiThread(() -> { Intent levelIntent = new Intent(mActivityContext, NextLevelActivity.class); ((Activity) mActivityContext).startActivity(levelIntent); // Optional: Finish the current game Activity if you don't want it in the back stack ((Activity) mActivityContext).finish(); }); } }
Step 3: Bonus: Clean up your code with an interface (best practice)
To avoid tight coupling between your Game class and Activity, use an interface callback. This way, the Game class only notifies when a level switch is needed, and the Activity handles the actual launch.
- Define the interface:
public interface LevelSwitchCallback { void onLevelReadyToSwitch(); }
- Add the callback to your Game class:
public class Game extends SurfaceView implements SurfaceHolder.Callback { private LevelSwitchCallback mCallback; // Add a setter for the callback public void setLevelSwitchCallback(LevelSwitchCallback callback) { mCallback = callback; } // When score hits threshold: if (playerScore >= targetScore && mCallback != null) { mCallback.onLevelReadyToSwitch(); } }
- Implement the callback in your hosting Game Activity:
public class GameHostActivity extends AppCompatActivity implements LevelSwitchCallback { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Game gameView = new Game(this); gameView.setLevelSwitchCallback(this); setContentView(gameView); } @Override public void onLevelReadyToSwitch() { startActivity(new Intent(this, NextLevelActivity.class)); finish(); } }
This keeps your Game class focused on game logic, not Android component navigation—much cleaner!
内容的提问来源于stack exchange,提问作者user4280144

