Android QA Audit
Systematically audit Android Java/Kotlin code for crash-prone patterns, memory leaks, and stability issues.
Workflow
Copy this checklist and track progress:
code
QA Audit Progress: - [ ] Step 1: Identify project structure (Activities, Fragments, Services, ViewModels) - [ ] Step 2: Scan for crash patterns (see crash-patterns.md) - [ ] Step 3: Scan for memory leak patterns (see memory-leaks.md) - [ ] Step 4: Generate severity-classified report - [ ] Step 5: Propose incremental fix phases
Step 1: Identify Project Structure
Locate all:
- •
ActivityandAppCompatActivitysubclasses - •
Fragmentsubclasses - •
Servicesubclasses - •
ViewModelsubclasses - •Custom
Viewsubclasses - •
BroadcastReceiversubclasses - •Singleton / companion object classes
Step 2: Scan for Crash Patterns
For each file found in Step 1, check every pattern in crash-patterns.md.
Key searches to run:
- •
!!-- force unwraps in Kotlin (potential NPE) - •
catch (with empty body or only comments -- swallowed exceptions - •
commit()on FragmentTransaction -- should becommitAllowingStateLoss()in async contexts - •
CoroutineScope(without lifecycle tie-in - •
runOnUiThreadorHandler.postfrom callbacks that may fire after destroy
Step 3: Scan for Memory Leak Patterns
For each file found in Step 1, check every pattern in memory-leaks.md.
Key searches to run:
- •
static.*Contextorcompanion.*context-- static Context references - •
new Handler()orHandler()withoutLooper-- deprecated, leak-prone - •
removeCallbacksAndMessages-- verify it exists inonDestroy/onDestroyView/onDetachedFromWindow - •
CompositeDisposable-- verify.dispose()or.clear()in lifecycle cleanup - •
BitmapFactory.decode-- verify.recycle()exists when done - •
registerListener/addListener-- verify matchingunregister/removein cleanup - •
onDestroy/onDestroyView/onDetachedFromWindow-- verify all resources are released
Step 4: Generate Report
Output a structured report using this template:
markdown
# QA Audit Report -- [Project Name] ## Critical (will crash in production) | # | File | Line | Issue | Recommended Fix | |---|------|------|-------|-----------------| ## High (likely crash or major leak) | # | File | Line | Issue | Recommended Fix | |---|------|------|-------|-----------------| ## Medium (potential leak or degraded stability) | # | File | Line | Issue | Recommended Fix | |---|------|------|-------|-----------------| ## Low (code quality, best practices) | # | File | Line | Issue | Recommended Fix | |---|------|------|-------|-----------------|
Severity Classification
- •Critical: Will crash under normal usage (force unwrap on nullable, missing null check on lifecycle-dependent field)
- •High: Will crash under specific conditions or cause major memory leak (Handler leak keeping Activity alive, unscoped coroutine updating destroyed UI)
- •Medium: Potential leak or degraded stability (deprecated API, missing cleanup that GC usually handles, broad catch blocks)
- •Low: Best practice violation with minimal runtime impact (empty catch with logging, using
commit()vscommitAllowingStateLoss())
Step 5: Propose Incremental Fix Phases
Group fixes into testable phases ordered by:
- •Risk level (lowest risk first)
- •File locality (changes to same file grouped together)
- •Dependency (fixes that enable other fixes first)
Each phase should:
- •Touch as few files as possible (ideally 1-2)
- •Be testable independently
- •Include specific test instructions
Additional Resources
- •For detailed crash patterns, see crash-patterns.md
- •For detailed memory leak patterns, see memory-leaks.md