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

Android API<28启动其他Activity后View.setVisibility(View.VISIBLE)失效问题

Android API27及以下启动Activity返回后View显示异常问题解决

嘿,我仔细看了你的问题,这确实是个挺烦人的API兼容性问题——在API27及以下版本,启动同意表单、评分或者插屏广告这类外部Activity返回后,原本设为gone的GameOver布局要么显示不出来,要么setText不生效,哪怕日志显示状态已经是VISIBLE了对吧?

我帮你梳理下问题根源和可行的解决方案:

为什么会出现这个问题?

  1. View引用失效:你在showHighscore里每次都调用gameOver = act.findViewById(R.id.GameOver);,如果启动其他Activity后系统因为内存紧张回收了当前Activity,返回时Activity会重建,这时候你拿到的View引用可能是旧实例的,哪怕设置了VISIBLE,旧实例已经不在当前界面上了。
  2. UI刷新没触发:从后台返回后,某些情况下布局的重绘请求没有被系统正确处理,导致状态更新了但界面没变化。
  3. 线程阻塞导致生命周期异常:你的onPause方法里有个无限循环等待线程join,这可能卡住Activity的暂停流程,进而影响后续Resume时的UI状态。

具体解决方案

1. 缓存View引用,别每次都findViewById

把View引用在Activity的onCreate里初始化一次,之后复用,别每次调用方法都重新查找:

// 在你的Activity类里声明成员变量
private LinearLayout gameOver;
private TextView score;
private TextView highScore;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_layout_id); // 替换成你的布局ID
    // 一次性初始化所有需要用到的View
    gameOver = findViewById(R.id.GameOver);
    score = findViewById(R.id.Score);
    highScore = findViewById(R.id.HighScore);
}

// 修改showHighscore方法,去掉重复查找的代码
public void showHighscore(int s, int hs) {
    System.out.println("Visibility before: " + gameOver.getVisibility());
    score.setText("Your Score: " + s);
    highScore.setText("HighScore: " + hs);
    gameOver.setVisibility(View.VISIBLE);
    // 强制触发View和父布局的刷新
    gameOver.invalidate();
    View parent = (View) gameOver.getParent();
    if (parent != null) {
        parent.requestLayout();
    }
    System.out.println("Visibility after: " + gameOver.getVisibility());
    System.out.println("NORMAL HIGHSCORE");
}

2. 修复onPause里的线程阻塞问题

你原来的onPause里用了无限循环等待线程join,这会导致Activity无法正常完成暂停流程,给join加个超时时间:

@Override
public void onPause() {
    super.onPause();
    Units.kill = true;
    System.out.println("Killing");
    sound.stopSounds();
    if (animThread != null && animThread.isAlive()) {
        try {
            animThread.join(1000); // 设置1秒超时,避免无限卡住
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        animThread = null;
    }
}

3. 确保在Activity活跃状态下更新UI

从其他Activity返回后,Activity会经历onResume,如果游戏线程在Activity还没完全Resume时触发更新,可能会无效。可以加个状态标志:

private boolean isActivityResumed = false;
private int pendingScore = -1;
private int pendingHighScore = -1;

@Override
protected void onResume() {
    super.onResume();
    isActivityResumed = true;
    // 你的原有onResume逻辑...
    // 检查有没有待处理的显示请求
    if (pendingScore != -1) {
        showHighscore(pendingScore, pendingHighScore);
        pendingScore = -1;
        pendingHighScore = -1;
    }
}

@Override
protected void onPause() {
    super.onPause();
    isActivityResumed = false;
    // 你的原有onPause逻辑...
}

// 线程触发时先检查状态
activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        if (activity.isActivityResumed) {
            activity.showHighscore(score, original);
        } else {
            // 暂时保存状态,等Resume时再显示
            activity.pendingScore = score;
            activity.pendingHighScore = original;
        }
    }
});

4. 针对API27及以下的额外处理

在低版本系统中,有时候父布局不会自动感知子View的状态变化,手动触发父布局的重绘会更稳妥,这部分已经包含在第一个解决方案的showHighscore方法里了。

测试建议

先从修改showHighscore的View引用和添加强制刷新开始,这是最常见的原因。然后修复onPause的线程问题,再测试启动同意表单、评分功能后返回的场景,应该就能解决问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:34:09