You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android:屏幕旋转后Activity方向未始终切换问题求助

Fixing Activity Orientation Glitches After Screen Rotation

Hey there! Let's sort out that screen rotation issue with your Android drawing app. Looking at your code and the problem description, the main culprits are Android's default behavior of recreating the Activity during rotation, plus some missing handling for thread lifecycle and state persistence. Here's how to fix this step by step:

1. Quick Fix: Prevent Activity Recreation During Rotation

If your app doesn't need to load different resources for portrait/landscape, the fastest solution is to tell Android not to recreate your Activity when the screen rotates. Add this to your AndroidManifest.xml for your MainActivity:

<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|smallestScreenSize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Then override onConfigurationChanged in MainActivity to manually update the SurfaceView size when the orientation changes:

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    SurfaceView mainView = findViewById(R.id.mainView);
    if (mGameApp != null) {
        mGameApp.setSurfaceSize(mainView.getWidth(), mainView.getHeight());
    }
}

This skips the Activity recreation entirely, so your thread and drawing state stay intact.

2. Standard Fix: Save and Restore Activity State

If you do need the Activity to recreate (e.g., to load orientation-specific resources), you need to properly save and restore your app's state:

Step 2.1: Save Running State in onSaveInstanceState

Add this to MainActivity to save whether your game thread was running before rotation:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean("isThreadRunning", mGameApp != null && mGameApp.isRunning());
}

Note: Add a getter for mRun in GameApp to access the running state:

public boolean isRunning() {
    return mRun;
}

Step 2.2: Restore State in onCreate

Update your onCreate method to resume the thread if it was running before the rotation:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    SurfaceView mainView = findViewById(R.id.mainView);
    SurfaceHolder holder = mainView.getHolder();
    holder.addCallback(this);
    mGameApp = new GameApp(getResources(), holder);

    // Restore state if Activity is recreating
    if (savedInstanceState != null) {
        boolean wasRunning = savedInstanceState.getBoolean("isThreadRunning");
        mGameApp.setRunning(wasRunning);
    }
}

Step 2.3: Clean Up Thread Properly in surfaceDestroyed

Make sure you clear the thread reference when the Surface is destroyed to avoid leftover threads after recreation:

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    boolean retry = true;
    mGameApp.setRunning(false);
    while (retry) {
        try {
            if (mGameThread != null) {
                mGameThread.join();
                mGameThread = null; // Clear reference to avoid reuse
            }
            retry = false;
        } catch (InterruptedException e) {
            e.printStackTrace(); // Don't swallow exceptions—helps with debugging!
        }
    }
}

3. Optimize Drawing Logic for Consistency

Your current draw method reloads the cell Drawable every time it runs, which can cause performance hits and potential glitches during rotation. Initialize the Drawable once in GameApp's constructor instead:

public class GameApp {
    private Resources mResources;
    private SurfaceHolder mSurfaceHolder;
    private int mCanvasHeight = 1;
    private int mCanvasWidth = 1;
    private volatile boolean mRun = false;
    private Drawable cellImage; // Reusable Drawable instance

    public GameApp(Resources resources, SurfaceHolder surfaceHolder) {
        mResources = resources;
        mSurfaceHolder = surfaceHolder;
        cellImage = mResources.getDrawable(R.drawable.cell); // Initialize once
    }

    // ... rest of your methods ...

    private void draw(Canvas canvas) {
        canvas.drawColor(Color.GREEN);
        final float cellWidth = (float) mCanvasWidth / 6;
        final float cellHeight = (float) mCanvasHeight / 6;
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                float x = i * cellWidth;
                float y = j * cellHeight;
                cellImage.setBounds(Math.round(x), Math.round(y), 
                                   Math.round(x + cellWidth), Math.round(y + cellHeight));
                cellImage.draw(canvas);
            }
        }
    }
}

Why This Happened

  • Activity Recreation: By default, Android destroys and recreates your Activity when the screen rotates. This meant your old thread and GameApp instance were discarded, and the new instance didn't know to resume the drawing loop.
  • Surface Size Mismatch: Sometimes the surfaceChanged callback wasn't triggering correctly after recreation, leading to wrong canvas dimensions for drawing.
  • Drawable Reloads: Reinitializing the Drawable every frame wasted resources and could cause inconsistencies during configuration changes.

内容的提问来源于stack exchange,提问作者Denis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 22:47:32