Android ANR崩溃求助:处理SCREEN_ON广播时触发异常
Hey there, let's dig into why this ANR (Application Not Responding) is popping up when the android.intent.action.SCREEN_ON intent fires, and walk through how to fix it.
First, let's identify the root causes in your code:
- Way too frequent UI thread updates: You're using a
Timerthat fires every 500ms and posts a Runnable to the UI thread. That's 2 updates per second—way more than necessary for a banner rotation (most apps use 2-3 seconds between slides). When the screen wakes up, the system is already busy with a ton of background tasks, so this constant UI thread chugging is a surefire way to block the main thread and trigger an ANR. - Swallowed exceptions: All your
catch (Exception e) { }blocks are empty. This hides critical issues likeNullPointerException(e.g., iftvBannerTextis null because the Activity is destroyed, orbannerListgets cleared unexpectedly) orIndexOutOfBoundsException. These hidden errors can cause silent failures that eat up resources without you knowing. - Unmanaged Timer lifecycle: The
Timerkeeps running even after the Activity is destroyed. It holds a reference to the Activity, causing a memory leak, and keeps trying to update UI elements that no longer exist—wasting CPU cycles and worsening thread congestion. - SCREEN_ON broadcast context: This intent is delivered on the main thread. If you're starting this Timer directly from the broadcast receiver, you're adding heavy work to an already busy thread right when the screen wakes up.
Here's how to fix it step by step:
1. Replace Timer with a Handler (Android-friendly alternative)
Timer isn't the best choice for UI-related periodic tasks on Android—Handler is designed to work with the main thread's message queue and is easier to manage.
2. Tie the rotation to the Activity lifecycle
Start the rotation in onResume() and stop it in onPause()/onDestroy() to avoid leaks and unnecessary work when the app isn't visible.
3. Fix exception handling
Log exceptions instead of swallowing them so you can debug issues when they happen.
4. Reduce the rotation interval
Bump it to 2000-3000ms (2-3 seconds) to give the UI thread breathing room.
5. Add null safety checks
Make sure you're not accessing UI elements or data structures that might be null.
Modified code example:
private Handler bannerHandler = new Handler(Looper.getMainLooper()); private Runnable bannerRunnable; @Override protected void onResume() { super.onResume(); startBannerRotation(); } @Override protected void onDestroy() { super.onDestroy(); stopBannerRotation(); } private void startBannerRotation() { bannerRunnable = new Runnable() { @Override public void run() { try { if (bannerList != null && bannerList.size() > 0 && activity != null && !activity.isFinishing()) { int position = bsPromotion.getCurrentSlidePosition() - 1; // Use bannerList size instead of hardcoded 4 to avoid index errors position = position < 0 || position >= bannerList.size() ? 0 : position; if (tvBannerText != null) { tvBannerText.setTag(position); tvBannerText.setText(bannerList.get(position).title); } } // Schedule next run with a reasonable interval bannerHandler.postDelayed(this, 2000); } catch (Exception e) { // Log the exception to debug issues later Log.e("BannerRotation", "Error updating banner text", e); } } }; // Start the rotation immediately bannerHandler.post(bannerRunnable); } private void stopBannerRotation() { if (bannerHandler != null && bannerRunnable != null) { bannerHandler.removeCallbacks(bannerRunnable); } }
Additional tips:
- If this banner is part of a ViewPager or a dedicated carousel library, use the library's built-in auto-rotation feature instead of rolling your own—those are optimized for performance.
- If you're starting this from a
SCREEN_ONbroadcast receiver, don't run the rotation directly there. Instead, send a lightweight signal to your Activity (e.g., via a ViewModel or LocalBroadcastManager) to start the rotation only if the Activity is active.
内容的提问来源于stack exchange,提问作者user1159258

