Android开发问题:runOnUIThread中thread.join失效及返回键动画后关Activity失败
我来帮你搞定这两个Android开发里的常见问题!
问题1:使用
runOnUIThread时thread.join()无法正常工作 原因分析
首先得搞清楚runOnUIThread的本质:它只是把你传入的Runnable提交到UI线程的消息队列,等UI线程有空的时候才会执行。而thread.join()是让当前线程阻塞,直到目标线程执行完毕。这里的坑点主要有两个:
- 如果你的
join()是在UI线程调用的:UI线程会被阻塞,消息队列里的runOnUIThread任务根本没机会执行,直接形成死锁,自然看不到预期效果。 - 如果你的
join()是在子线程调用的:你等待的是子线程结束,但runOnUIThread的任务是在UI线程跑的,两者完全是不同的执行路径,join()根本管不到UI线程的任务,所以也达不到“等UI线程任务完成再继续”的目的。
解决方案
根据你的需求(等待UI线程任务完成后再继续),推荐几种靠谱的实现方式:
方式1:用CountDownLatch
在子线程里用Latch来等待UI任务完成:
// 子线程中执行 CountDownLatch latch = new CountDownLatch(1); runOnUiThread(() -> { // 你的UI操作逻辑 // ... latch.countDown(); // 任务完成,释放Latch }); try { latch.await(); // 阻塞子线程,直到UI任务完成 } catch (InterruptedException e) { e.printStackTrace(); } // 这里就是UI任务完成后要执行的逻辑
方式2:用Handler+Callback(适合Java)
把后续逻辑放到UI任务的末尾,或者用Handler发送消息通知:
private Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == 1) { // UI任务完成后要执行的逻辑 } } }; // 子线程中 runOnUiThread(() -> { // 你的UI操作 // ... mHandler.sendEmptyMessage(1); // 通知后续逻辑执行 });
方式3:用Kotlin协程(推荐Kotlin项目)
利用withContext切换到UI线程,协程会自动挂起等待任务完成:
lifecycleScope.launch(Dispatchers.IO) { // 子线程逻辑 withContext(Dispatchers.Main) { // UI线程操作 } // 这里会自动等待UI任务完成后再执行 }
问题2:按下返回键后先显示动画再结束Activity,代码未生效
原因分析
最常见的问题就是你直接在onBackPressed()里调用了finish(),导致Activity在动画开始前就被销毁了。动画是需要时间执行的,而finish()会立即触发Activity的销毁流程,动画还没来得及播放就没了。另外还有可能:
- 动画没有设置正确的监听器,没在动画结束时触发
finish(); - 动画是在子线程执行的,UI线程已经执行了
finish(); - 重写
onBackPressed()时没有拦截默认的返回逻辑,默认的finish先执行了。
解决方案
核心思路:拦截默认的返回逻辑,先启动动画,在动画完全结束后再调用finish()。
示例代码(Java)
假设你要给某个View播放退出动画:
@Override public void onBackPressed() { // 1. 拦截默认返回逻辑,不要直接super.onBackPressed() View targetView = findViewById(R.id.your_target_view); // 2. 创建并启动动画 Animation exitAnim = AnimationUtils.loadAnimation(this, R.anim.your_exit_anim); exitAnim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { // 3. 动画结束后再结束Activity finish(); // 如果需要带动画退出,可以加overridePendingTransition overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim); } @Override public void onAnimationRepeat(Animation animation) {} }); targetView.startAnimation(exitAnim); }
示例代码(Kotlin)
用ViewPropertyAnimator更简洁:
override fun onBackPressed() { val targetView = findViewById<View>(R.id.your_target_view) targetView.animate() .alpha(0f) // 举个例子:渐变消失动画 .translationY(100f) .setDuration(300) .withEndAction { // 动画结束后执行finish finish() overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right) } }
额外注意点
- 如果你的动画是针对整个Activity的,可以给Activity的根布局设置动画;
- 不要在动画过程中再次触发返回键,可以加个标志位防止重复操作;
- 如果用的是Fragment,要在Activity里拦截返回键,或者在Fragment中使用
OnBackPressedCallback来处理。
内容的提问来源于stack exchange,提问作者omid naghipoor
相关产品推荐
相关产品推荐

