Android应用在低版本系统崩溃问题排查及代码优化求助
Hey there! Let's break down why your app is crashing on the LGE V20 (Android 7.0) and get your code tuned up at the same time.
Root Cause of the Crash
Looking at your crash log:
java.lang.IllegalArgumentException: at java.util.Random.nextInt (Random.java:391) at tk.myessentialoils.reprogramyourmind.MyService$TimeDisplayTimerTask$1.run (MyService.java:92)
This error pops up when you pass a value ≤ 0 to Random.nextInt(int bound). In your code, that bound is array.length—so this means your array is empty (length = 0) when the crash happens. Your emulator has a populated array, which is why it works there, but the Android 7.0 device is hitting a scenario where the array isn't initialized properly or has no elements.
Code Fixes & Optimization
Let's go through key improvements to fix the crash and make your code more robust:
1. Guard Against Empty Array
First, add a check to ensure the array isn't empty before trying to pick a random element. If it's empty, you can skip showing the Toast or add a fallback message.
2. Reuse Random Instance
Creating a new Random object every time your timer runs is unnecessary. Create one instance once (e.g., in your MyService class) and reuse it for better performance.
3. Reuse Handlers Instead of Creating New Ones
You're making multiple Handler instances (mHandler, cancelToast) unnecessarily. Reuse a single Handler from your Service where possible to avoid redundant object creation.
4. More Robust Toast Handling
Calling Notify.cancel() can be unreliable on some Android versions. Reusing your existing mHandler for the delayed cancel helps keep things consistent.
Modified Code Example
Here's how your updated TimeDisplayTimerTask could look:
// Add a reusable Random instance in your MyService class private final Random random = new Random(); private class TimeDisplayTimerTask extends TimerTask { @Override public void run() { mHandler.post(new Runnable() { @Override public void run() { // Guard against empty or null array if (array == null || array.length == 0) { // Optional fallback message Toast.makeText(getApplicationContext(), "No messages available right now", Toast.LENGTH_SHORT).show(); return; } // Reuse the global Random instance String randomStr = array[random.nextInt(array.length)]; final Toast notify = Toast.makeText(getApplicationContext(), randomStr, Toast.LENGTH_LONG); // Customize Toast styling TextView toastMessage = (TextView) notify.getView().findViewById(android.R.id.message); toastMessage.setTextColor(Color.RED); toastMessage.setTextSize(21); notify.getView().setBackgroundColor(Color.TRANSPARENT); notify.setGravity(Gravity.CENTER, 0, 0); notify.show(); // Reuse mHandler for delayed cancel mHandler.postDelayed(new Runnable() { @Override public void run() { notify.cancel(); } }, DISPLAYTIME); } }); } }
Additional Checks to Prevent Future Crashes
- Verify Array Initialization: Double-check where your
arrayis being populated. Make sure it's fully initialized before this timer runs—older Android versions might handle async setup differently than your emulator. - Test on Low-Version Emulators: Use Android 7.0 (API 24) and lower emulators to catch similar issues early in development.
- Watch for Memory Leaks: If this timer runs for long periods, consider using a static inner class with a weak reference to your Service to avoid holding onto the Service instance unnecessarily.
内容的提问来源于stack exchange,提问作者Tony Ming

