Android API<28启动其他Activity后View.setVisibility(View.VISIBLE)失效问题
Android API27及以下启动Activity返回后View显示异常问题解决
嘿,我仔细看了你的问题,这确实是个挺烦人的API兼容性问题——在API27及以下版本,启动同意表单、评分或者插屏广告这类外部Activity返回后,原本设为gone的GameOver布局要么显示不出来,要么setText不生效,哪怕日志显示状态已经是VISIBLE了对吧?
我帮你梳理下问题根源和可行的解决方案:
为什么会出现这个问题?
- View引用失效:你在
showHighscore里每次都调用gameOver = act.findViewById(R.id.GameOver);,如果启动其他Activity后系统因为内存紧张回收了当前Activity,返回时Activity会重建,这时候你拿到的View引用可能是旧实例的,哪怕设置了VISIBLE,旧实例已经不在当前界面上了。 - UI刷新没触发:从后台返回后,某些情况下布局的重绘请求没有被系统正确处理,导致状态更新了但界面没变化。
- 线程阻塞导致生命周期异常:你的
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
相关产品推荐
相关产品推荐

