When fixing bugs in an Android app project, it's crucial to not just patch the issue, but to ensure stability, performance, and maintainability of the app. Here's a structured list of key areas to address during bug fixing:
1. Reproduce and Isolate the Bug
-
Reproduce the issue consistently in a local or QA environment.
-
Logcat analysis: Use
Log.d
,Log.e
,Timber
, etc., to check stack traces and contextual logs. -
Crash reports: Utilize tools like Firebase Crashlytics, Sentry, or Bugsnag to identify the root cause.
-
Debug tools: Use Android Studio debugger, breakpoints, or Flipper for runtime inspection.
2. Identify Root Cause (Not Just Symptoms)
-
Avoid surface-level fixes that mask the issue.
-
Trace through stack traces, thread state, and lifecycle behavior.
-
Use techniques like binary search debugging, rollback comparison, or
git bisect
.
3. Check Affected Scope and Dependencies
-
Understand the scope: What modules/features are impacted?
-
Review dependencies (third-party libraries, APIs, database, sensors, etc.).
-
Check for side effects or hidden regressions in related components.
4. Fix Using Best Practices
-
Apply Kotlin null safety, immutability, lifecycle awareness, and coroutine exception handling.
-
Respect architecture (e.g., Clean Architecture, MVVM).
-
Avoid memory leaks (e.g., by cleaning up observers or references in
onCleared()
oronDestroy()
).
5. Test the Fix Thoroughly
-
Unit test the logic.
-
UI/Instrumentation tests (e.g., using Espresso).
-
Edge cases: test on different devices, orientations, languages, and API levels.
-
Use mock data and real-world scenarios.
-
Automate via CI/CD if possible.
6. Code Review & PR Standards
-
Push changes to a feature or hotfix branch.
-
Follow team PR templates/checklists.
-
Include before/after behavior screenshots or videos (especially for UI bugs).
-
Peer review for readability, performance, and maintainability.
7. Update Logs, Metrics, and Documentation
-
Update
CHANGELOG.md
or release notes. -
Add JIRA/Trello references and resolution notes.
-
If it's a backend-related issue, sync with backend devs.
-
If API contract changes, update API schema or versioning.
8. Deploy Carefully
-
Use staged rollout (e.g., Play Console’s percentage rollout).
-
Monitor logs and crash analytics post-deploy.
-
Add feature flags if needed for emergency disable.
9. Retrospective or Root Cause Analysis (RCA)
-
Log the root cause and learnings in a shared document.
-
Improve test coverage or monitoring based on the gap.
-
Share insights with the team in sprint retro or knowledge base.
Tools That Help:
Category | Tool |
---|---|
Logging | Timber, Logcat, Crashlytics |
Debugging | Android Studio, Flipper, LeakCanary |
Monitoring | Firebase Performance, Sentry |
Testing | JUnit, Espresso, MockK, Robolectric |
CI/CD | GitHub Actions, Bitrise, Jenkins |
Issue Tracking | Jira, Trello, Linear |
Here’s a realistic example of a bug fix in an Android app, including the bug description, root cause, fix implementation, and testing strategy.
Example : App Crashes on Orientation Change While Loading Data
Bug Report
-
Title: App crashes when rotating screen during data loading on
ProfileFragment
. -
Severity: High (crashes app)
-
Environment: Android 12, Pixel 5, API 31
-
Steps to Reproduce:
-
Open the app and navigate to Profile tab.
-
While the data is loading (loading spinner showing), rotate the screen.
-
App crashes with
IllegalStateException
.
-
Crash Log
java.lang.IllegalStateException: ViewModel not attached to lifecycle yet
at ProfileViewModel.getProfileData(ProfileViewModel.kt:45)
Root Cause
-
The
ProfileFragment
was trying to observe LiveData before the view was fully recreated after orientation change. -
The data load was tied to the fragment’s
onCreateView
rather thanviewLifecycleOwner
.
Fix
Refactor LiveData observer to bind with viewLifecycleOwner
instead of the fragment's lifecycle.
// Before (incorrect)
viewModel.profileLiveData.observe(this, Observer {
// update UI
})
// After (correct)
viewModel.profileLiveData.observe(viewLifecycleOwner, Observer {
// update UI
})
Additionally, use repeatOnLifecycle
for Kotlin Flow in Compose or ViewModel coroutine collection:
lifecycleScope.launch {
viewLifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.profileFlow.collect {
// Update UI
}
}
}
Testing Done
-
Rotated device multiple times during and after data load.
-
Verified no crashes on API 30, 31, 34.
-
Verified ViewModel data not lost.
-
Espresso UI test added for rotation.
PR Notes
๐ Fixed crash on orientation change in
ProfileFragment
by usingviewLifecycleOwner
for LiveData observer. Added test for configuration change handling.
JIRA Ticket:APP-2931
Impact: Profile screen lifecycle handling.
Improvement
Added lifecycle-aware logging to catch future orientation-related issues:
Log.d("Lifecycle", "ProfileFragment state: ${lifecycle.currentState}")
๐ข Feedback: Did you find this article helpful? Let me know your thoughts or suggestions for improvements! ๐ please leave a comment below. I’d love to hear from you! ๐
Happy coding! ๐ป✨
0 comments:
Post a Comment