Skip to content
10 Common Non-Crashing Bugs and How to Fix Them

14 Minutes

10 Common Non-Crashing Bugs and How to Fix Them

Fix Bugs Faster! Log Collection Made Easy

Get started

Non-crashing bugs don’t make your app crash, but they can ruin the user experience and hurt your app’s ratings. Fixing these issues is critical to keeping users happy. Here’s a quick rundown of the most common non-crashing bugs and how to address them:

  • Screen Layout Problems: Misaligned or overlapping UI elements. Use tools like Android Studio’s Layout Inspector or Xcode’s View Hierarchy Debugger to spot and fix these issues.
  • Data Loss During Background Tasks: Prevent data loss by managing background tasks properly, using custom storage solutions, and validating data integrity.
  • Wrong Date and Number Formats: Ensure proper formatting for dates, numbers, and currencies using locale-specific tools like DateFormatter (iOS) or SimpleDateFormat (Android).
  • Deep Link Failures: Fix navigation issues caused by improper setup or OS restrictions by configuring deep links correctly and testing thoroughly.
  • List View Memory Issues: Optimize memory usage in scrolling lists to prevent laggy performance by recycling unused resources and avoiding memory leaks.
  • Slow Push Notifications: Speed up notifications by managing tokens, improving network handling, and monitoring delivery performance.

Why It Matters

Non-crashing bugs might not seem urgent, but they can lead to slow performance, user frustration, and poor app reviews. By addressing these issues, you can improve user satisfaction and maintain strong app ratings.

Quick Tip: Regularly test your app on multiple devices and OS versions to catch these bugs early.

Want to dive deeper? Keep reading for actionable fixes for each bug type.

Debugging Like a Pro: Expert Strategies for Diagnosing and Fixing Android Bugs

1. Screen Layout Problems

Screen layout issues – like inconsistent designs, overlapping elements, or misaligned views across devices and resolutions – can make an app harder to use.

Spotting Layout Bugs

Tools like Android Studio’s Layout Inspector and Xcode’s View Hierarchy Debugger are great for finding UI problems. These tools let you inspect views and uncover issues such as:

Layout IssueImpactDetection Method
Overlapping ElementsHard to read contentComponent Tree inspection
Incorrect ConstraintsBroken layoutsAttributes tool window
Density IssuesInconsistent sizingVisualization
Runtime Layout ChangesUnexpected positioningLayout snapshots

For example, Android Studio’s Layout Inspector allows live debugging, letting you examine individual views and their properties. This makes it easier to pinpoint and fix layout issues, ensuring your app looks good on all devices.

Fixing Layout Bugs

Modern UI frameworks like Jetpack Compose and SwiftUI make fixing layout bugs simpler. Here’s how:

Responsive Layouts

“Creating adaptive layouts in Jetpack Compose is easier than ever. As a declarative UI toolkit, Jetpack Compose is well suited for designing and implementing layouts that adjust themselves to render content differently across a variety of sizes.”

Handling Dynamic Content

Take inspiration from the JetLagged app (October 2024), which used FlowRow to limit items to three per row, optimizing dashboard space [1].

Framework-Specific Tools

  • In SwiftUI, use ViewThatFits to display the view that best fits the available space [2].
  • For Jetpack Compose, leverage BoxWithConstraints to adjust content based on screen dimensions [3].

Key Layout Improvements

  • Set proper layout attributes for consistent alignment [4].
  • Design layouts that work with density-independent pixels.
  • Use FlowRow and FlowColumn for responsive arrangements [5].
  • Add smooth transitions with the animateBounds modifier [6].

These steps help ensure your app delivers a polished and functional experience, even as you tackle other non-critical bugs.

2. Data Loss During Background Tasks

Losing data during background tasks can harm user experience, even if the app doesn’t crash. This issue arises when apps switch between active and background states, potentially leading to corrupted or missing data.

Signs of Data Loss

Data loss during background activities often presents itself in specific ways:

Warning SignImpactCommon Scenario
Missing User PreferencesSettings unexpectedly resetApp relaunch after device reboot
Incomplete Background SavesData updates fail silentlyApp suspended during save
Corrupted StateInconsistent data between sessionsTask interrupted in the background
Failed Resume StateLoss of user progressMemory pressure events

These problems are particularly common when apps use UserDefaults for saving data. iOS encryption can make this storage temporarily inaccessible during background launches, compounding the issue.

Preventing Data Loss

Avoiding data loss in background tasks requires careful debugging and thoughtful implementation.

Verify System State

Before performing operations, ensure the system is ready. Use UIApplication.isProtectedDataAvailable to confirm data accessibility, especially after device reboots or during Live Activities.

Use Custom Data Storage

Build a more reliable storage solution by writing directly to the app’s shared container directory. For example:

let queue = DispatchQueue(label: "com.app.storage")
queue.async {
    // Perform thread-safe operations
    // Use Codable for serialization
}

Manage Background Tasks Properly

Keep a close eye on the lifecycle of background tasks. As Christian Selig explains: “The whole point of UserDefaults is that it’s supposed to reliably store simple, non-sensitive data so it can be accessed whenever. The fact that this has now changed drastically, and at the same time your app can be launched effectively whenever, makes for a complex and challenging scenario.”

Perform Data Integrity Checks

Validate new data before overwriting existing information, particularly during background launches when UserDefaults may be temporarily unavailable. Incorporate error handling and logging to identify and fix data issues. Use background task completion handlers to ensure critical processes finish before the app is suspended.

Preventing data loss in background tasks is just as important as fixing layout issues when it comes to building a dependable app.

3. Wrong Date and Number Formats

Incorrect date and number formats can confuse users and lead to misunderstandings.

Format Error Examples

Here are some common formatting issues and their impact:

Error TypeIncorrect FormatCorrect Format (US)Impact
Date Display2022-01-31T16:27:23ZJan 31, 2022, 11:27 AMCauses user confusion
Currency1234.56$1,234.56Leads to financial errors
Large Numbers10000001,000,000Hard to read
Time Zones17:27 UTC12:27 PM ESTMisinterpreted schedules

Some real-world scenarios include:

  • News feeds showing timestamps in UTC instead of the user’s local time.
  • Currency values displayed without symbols or proper separators.
  • Analytics dashboards missing thousand separators for large numbers.
  • Date inputs accepting formats that don’t align with the user’s locale.

Format Error Solutions

To avoid these issues, ensure proper locale-specific formatting:

iOS (Swift/SwiftUI) Implementation

Use Locale.current to format currency:

Text(amount, format: .currency(code: Locale.current.currency?.identifier ?? "USD"))

Android (Kotlin/Jetpack Compose) Implementation

For date formatting, use the default locale:

val formatter = SimpleDateFormat.getDateTimeInstance(
    DateFormat.MEDIUM,
    DateFormat.SHORT,
    Locale.getDefault()
)

Best Practices for Both Platforms

  • Maintain Currency Precision: Use Swift’s Decimal or Kotlin’s BigDecimal for accurate financial calculations. These types help prevent rounding errors.
  • Use Relative Dates: Show dates like “Today” or “Yesterday” instead of fixed timestamps, ensuring localization is applied.
  • Test Across Locales:
    • Set devices to different regions to verify formats.
    • Confirm currency symbols and placement.
    • Check thousand separators and date/time patterns.
  • Rely on System Formatters:
    • iOS: Use NumberFormatter and DateFormatter.
    • Android: Use NumberFormat.getCurrencyInstance() and SimpleDateFormat.

Next, we’ll dive into common causes of deep link failures and how to resolve them effectively.

4. Deep Link Failures

Deep link failures can disrupt navigation and negatively impact the user experience. These issues often remain unnoticed until users encounter navigation problems or abandon sessions.

Common Deep Link Errors

Here are some typical deep link issues:

Error TypeDescriptionImpact
Installation StatusLinks break after app installationUsers lose context post-installation
Device FragmentationInconsistent behavior across platformsVarying experiences on iOS and Android
Security RestrictionsOS-level blocks on specific linksCauses navigation failures
Data TransmissionContext loss during routingBreaks personalization and continuity

With Android 12’s stricter domain verification, generic web intents now only resolve to app activities if the app is explicitly approved for the domain. This change has led to previously functioning deep links failing unexpectedly [7]. Below are solutions to address these problems effectively.

Fixing Deep Link Issues

Fixing these errors improves navigation and boosts user engagement.

Platform-Specific Fixes

For Android:

// Ensure the manifest handles deep links properly
<activity android:name=".MainActivity">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="https" />
    </intent-filter>
</activity>

For iOS:

// Handle universal links in SceneDelegate
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
          let url = userActivity.webpageURL else {
        return
    }
    processDeepLink(url)
}

Testing and Validation

Use Android Debug Bridge (ADB) to test deep links:

adb shell am start -W -a android.intent.action.VIEW -d "your-deep-link-url"

Best Practices for Reliable Deep Linking

  • Use deferred deep links to manage cases where the app isn’t installed.
  • Set up fallback routes for when deep links fail.
  • Test across multiple OS versions and device types.
  • Monitor performance with logging and analytics tools.

“Deep links are simply the best way to build a quality, connected user experience that will bring in new customers and keep the ones you have engaged and happy.” – Megan Dobransky [6]

When implementing fixes, focus on:

  • Route Configuration: Properly set up URI schemes and universal links.
  • Data Continuity: Preserve user context during installations and updates.
  • Error Handling: Create fallback mechanisms for failed links.
  • Security Compliance: Follow platform-specific security guidelines.
  • Comprehensive Testing: Test functionality across various scenarios and devices.

5. List View Memory Issues

List view memory problems can slow down your app’s performance without causing it to crash. These issues often appear in Android’s RecyclerView and iOS’s LazyVGrid, leading to laggy scrolling and draining the battery faster than expected.

Identifying Memory Problems

On Android, the heap may hold onto unused memory. For instance, a single photo from a Pixel phone can take up around 48MB of memory when using the ARGB_8888 bitmap configuration [7].

Here are some common causes of memory issues:

Issue TypeImpactCommon Cause
Static ReferencesPermanent Memory LeaksUI components stored as static variables
Background Thread LeaksGrowing Memory UsageUI references in background tasks
Circular ReferencesMemory Not ReleasedAdapters indirectly referencing Activities
Image CachingExcessive Memory UsageMismanaged bitmap handling and recycling

Fixing Memory Problems

Here are some practical solutions to handle memory issues in scrolling lists:

Optimizing Android RecyclerView

// Clear adapter references to avoid leaks
override fun onDestroyView() {
    super.onDestroyView()
    recyclerView.adapter = null
}

Managing Image Memory

// Properly recycle bitmaps when they're no longer needed
bitmap?.let {
    if (!it.isRecycled) {
        it.recycle()
    }
}

“Android UI components are not thread-safe. It’s possible to kill an Activity but this does not necessarily kill a background thread. Because of this volatile complexity, memory leaks are possible as any instances of a component can easily turn into dead weight.” [7] – Amanda Hinchman, Google Developer Experts

Best Practices for Memory Optimization

For Jetpack Compose:

  • Use remember{ } blocks to maintain state without triggering unnecessary recompositions.
  • Add @Stable and @Immutable annotations to data classes to reduce redundant updates.
  • Manage keys properly in LazyColumn to track items efficiently.
  • Use lightweight image formats and apply compression to save memory.

For SwiftUI:

  • Opt for List instead of LazyVGrid when possible, as it handles memory better.
  • Implement effective image caching strategies.
  • Analyze memory usage during scrolling to identify problem areas.

Proper cleanup is critical to avoiding memory leaks. Mark inner classes as static, ensure UI updates happen on the main thread, and manage disposable resources like those in RxJava to prevent lingering memory issues.

Up next: how to speed up push notifications to keep your app running smoothly.

6. Slow Push Notifications

Slow push notifications can frustrate users, especially when they miss time-sensitive alerts. While these delays may not crash the app, they often go unnoticed until users start reporting problems.

Push Notification Challenges

Delays in push notifications can arise from several factors, including token management, network issues, device settings, and server configurations. Here’s a quick breakdown of common issues:

Issue TypeImpactRoot Cause
Token ManagementFailed DeliveryExpired or invalid push tokens
Network HandlingDelayed MessagesPoor connection management
Device SettingsBlocked AlertsOS-level restrictions
Server ConfigurationQueue BottlenecksImproper rate-limiting setup

Fixing these issues is essential to maintaining a responsive app experience.

How to Speed Up Notifications

Addressing push notification delays requires targeted strategies. Below are some effective ways to ensure timely delivery and improve user experience.

Token Management and Validation

Regularly refreshing and validating tokens ensures accurate delivery. Here’s an example in Kotlin:

// Refresh tokens during app launch or user login
override fun onResume() {
    super.onResume()
    FirebaseMessaging.getInstance().token
        .addOnSuccessListener { token ->
            updateServerWithNewToken(token)
        }
}

Improved Network Handling

Retry mechanisms can help manage delivery failures caused by network issues. Here’s a Swift example:

// Retry failed push notification deliveries
func scheduleRetry(for notification: PushNotification) {
    let retryCount = 3
    let retryInterval = 5.0 // seconds

    for attempt in 1...retryCount {
        DispatchQueue.main.asyncAfter(deadline: .now() + Double(attempt) * retryInterval) {
            self.sendNotification(notification)
        }
    }
}

Additional Optimization Tips

  • Prioritize Important Messages: Mark critical notifications as high-priority to reduce delays using Google Play Services.
  • Track Delivery Status: Use silent push notifications to monitor delivery success and keep tokens updated.
  • Send at the Right Time: Smart scheduling can increase engagement by up to 2.6×.

Monitoring and Debugging

It’s crucial to monitor metrics like delivery success rates, dispatch-to-delivery times, token refresh events, and user engagement. For iOS, use Console.app on macOS to filter push notification logs by searching for com.apple.pushLaunch. This helps identify and solve delivery issues quickly.

For example, KFC India’s “Bucket It” campaign saw impressive results: a 22% boost in daily orders, a 23% increase in revenue per store, and a 27% rise in repeat orders. These outcomes highlight the importance of timely and efficient push notifications.

Conclusion: Better Bug Detection and Fixes

Non-crashing bugs can hurt both user experience and app performance, making it critical to detect and resolve them systematically.

Key Focus Areas

Effective debugging involves a mix of monitoring and analysis. Here’s a quick breakdown:

Area of DebuggingTools to UseHow It Helps
Performance TestingXcode Instruments, Android ProfilerSpots bottlenecks and UI sluggishness
Code AnalysisIDE debugging tools, logging systemsIdentifies logic errors early
Memory ManagementMemory profilers, leak detectorsAvoids performance drops over time
Network MonitoringNetwork inspection toolsEnsures smooth data flow

Steps to Implement

Take these actions to enhance your app’s stability and overall performance:

1. Set Up Monitoring Systems

  • Add logging points throughout your code to track behavior.
  • Use analytics tools to monitor how your app performs in real-world scenarios.
  • Keep an eye on memory usage across different devices.

2. Streamline Your Development Process

  • Place breakpoints strategically to debug code in real-time.
  • Incorporate automated tests to cover essential app functions.

3. Prioritize User Experience

  • Test your app on various devices and operating systems.
  • Evaluate its performance under different network conditions.
  • Include error handling to ensure the app fails gracefully when issues arise.

FAQs

How can I test my app on different devices and OS versions to find non-crashing bugs early?

To catch non-crashing bugs early, it’s essential to test your app on a variety of devices and operating system versions. Start by using real devices whenever possible, as they provide more accurate results compared to emulators or simulators. Focus on testing across different screen sizes, resolutions, and hardware configurations to ensure your app performs consistently.

Prioritize testing on the most popular devices and OS versions used by your target audience. This approach helps you catch potential issues that could impact a significant portion of your users. If access to physical devices is limited, consider cloud-based testing services that provide remote access to a wide range of real devices. These strategies will help you identify and resolve subtle issues before they affect the user experience.

How can I manage background tasks effectively to avoid data loss in mobile apps?

To prevent data loss during background tasks, follow these best practices for mobile app development:

  • Use reliable tools: On Android, implement WorkManager to ensure tasks continue even if the app is closed or the device restarts. For smoother background operations, leverage Kotlin Coroutines for efficient handling of tasks, especially those interacting with the UI thread.
  • Be lifecycle-aware: Tie background tasks to component lifecycles using lifecycle-aware components to avoid issues like memory leaks or tasks running unnecessarily.
  • Handle constraints and errors: Ensure tasks only run under suitable conditions (e.g., device is charging or connected to Wi-Fi). Include retry mechanisms to recover from failures and maintain a seamless user experience.

For user-visible tasks, consider using foreground services with notifications to keep users informed while optimizing resource usage to avoid excessive battery drain or data consumption. These steps will help maintain app reliability and improve the overall user experience.

How can I ensure push notifications are delivered on time and remain effective for users?

To ensure push notifications are timely and effective, focus on sending them when users are most likely to engage. Track user activity and time zones to schedule notifications during active hours. Adjust the Time-to-Live (TTL) for messages to match their urgency, ensuring important notifications don’t expire before delivery.

If a notification fails to reach a user, implement retry mechanisms or fallback options, such as text messages, for critical alerts. Additionally, consider complementing push notifications with an in-app notification center to provide users with a reliable way to access important updates at their convenience.

Expect The Unexpected!

Debug Faster With Bugfender

Start for Free
blog author

Aleix Ventayol

Aleix Ventayol is CEO and co-founder of Bugfender, with 20 years' experience building apps and solutions for clients like AVG, Qustodio, Primavera Sound and Levi's. As a former CTO and full-stack developer, Aleix is passionate about building tools that solve the real problems of app development and help teams build better software.

Join thousands of developers
and start fixing bugs faster than ever.