Client
A mobile product company developing a feature-rich Android application handling:
-
Image/video processing
-
Network-heavy operations
-
Background syncing
-
Large data parsing
-
Sensor/event handling
Their single-process app experienced:
-
UI freezes
-
ANR (Application Not Responding) reports
-
High memory usage in the main process
-
Performance degradation on mid-range devices
They needed a multi-process architecture to separate heavy workloads from the UI process.
Project Overview
We redesigned the application into a multi-process Android architecture using:
-
AIDL (Android Interface Definition Language)
-
Bound services vs unbound services
-
Background worker processes
-
Process isolation to prevent UI blocking
-
Optimized IPC (Inter-process Communication) patterns
The goal was to improve UI responsiveness, increase stability, and reduce crashes/ANRs on all device categories.
Key Challenges
1. Heavy Logic Executed on Main App Process
CPU-intensive and memory-heavy operations caused:
-
Jank and lag
-
ANRs
-
UI thread blocking
2. IPC Communication Complexity
Moving tasks to another process required safe, thread-aware communication.
3. Lifecycle Management
Services needed to stay running independently without leaking resources.
4. Ensuring Stability on Lower-End Devices
Older devices were more sensitive to:
-
Memory allocations
-
Process restarts
-
Parallel execution
Our Solution
1. Multi-Process Application Design
We configured the AndroidManifest to run critical components in separate processes:
-
:workerprocess for heavy tasks -
:mlprocess for ML/computer vision tasks -
:networkprocess for API sync tasks -
Main process for UI only
Each component ran with its own memory and thread pool.
2. Implementing AIDL for IPC
We created AIDL interfaces for safe communication between processes:
AIDL was used for:
-
Sending tasks to background processes
-
Returning results async
-
Managing callbacks and listeners
-
Exchanging structured data
-
Running long-lived background operations
Benefits:
-
Strong typing
-
Version-safe APIs
-
Asynchronous, thread-safe communication
3. Bound vs Unbound Services Comparison
Bound Services
Used for tasks requiring:
-
Direct IPC with live callbacks
-
Result delivery back to UI
-
Tight synchronization
-
Interaction with user-driven operations
Bound services allowed:
-
Two-way communication
-
Easy lifecycle control tied to app components
Examples:
Video processing, ML inference, live rendering.
Unbound (Started) Services
Used for:
-
Long background jobs
-
Scheduled work
-
Operations that must continue independently
Examples:
Database sync, log upload, long computations.
Clear separation ensured each task type ran in the correct process with optimal resource usage.
4. Background Process Optimization
We optimized worker processes with:
-
Dedicated thread pools
-
Lower priority for non-interactive tasks
-
Memory constraints to avoid OOM
-
Graceful process restarts on failures
-
Foreground service support when required
This kept all heavy work away from the UI process.
5. Reducing UI Thread Workload
After migration:
-
UI handled only rendering + lightweight logic
-
No compute-heavy tasks ran in the main process
-
Input responsiveness improved significantly
6. Monitoring, Debugging & Stability Tools
We added:
-
Process-level logging
-
StrictMode for thread misuse detection
-
Performance traces using Perfetto
-
Crashlytics process-specific diagnostics
This enabled precise tracking of each process’s behavior.
Architecture Diagram (Text Version)
Results & Impact
Reduced ANRs
Heavy tasks moved out of main process eliminated UI freeze issues.
Improved UI Responsiveness
Main process became lightweight, improving FPS and navigation smoothness.
Increased App Stability
Crash rate decreased significantly on mid-range/low-end devices.
Parallelism Improved
Multiple processes allowed simultaneous workloads without blocking.
Scalable Architecture
Easy to add new worker processes for future modules like ML or media.
Conclusion
By migrating to a multi-process Android architecture using AIDL and bound/unbound services, we delivered a stable, smooth, and scalable application. Heavy background tasks were isolated into separate processes, ensuring the UI remained responsive even under complex workloads.
The final architecture significantly improved:
-
Performance
-
Stability
-
User experience
-
Developer control over workloads
This approach is ideal for large, computation-heavy Android apps.

Written by
Oliver Thomas
Oliver Thomas is a passionate developer and tech writer. He crafts innovative solutions and shares insightful tech content with clarity and enthusiasm.




