← back

Why I stopped polling and started listening — building a sub-100ms app detector on Android

20246 min read

Most Android developers reach for a polling loop when they need to monitor what's running on the device. Set a timer, check every 500ms, react when you see the right package. Simple. Obvious. Wrong.

I learned this the hard way building CONTROL, a sleep enforcement app that blocks TikTok, Instagram, and YouTube during restricted hours. My first implementation polled every 500ms using a Handler. It worked — barely. The detection latency was acceptable but the battery drain was not, and Android 12's background restrictions killed the loop within minutes of the screen turning off.

The event-driven alternative

Android's AccessibilityService exposes a stream of UI events including TYPE_WINDOW_STATE_CHANGED — fired every time a new window comes to the foreground. Instead of asking "what's running right now?" every 500ms, you simply listen for the operating system to tell you.

The implementation looks deceptively simple:

override fun onAccessibilityEvent(event: AccessibilityEvent) {
    if (event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
        val packageName = event.packageName?.toString() ?: return
        if (packageName in MONITORED_PACKAGES && isWithinRestrictedHours()) {
            triggerEnforcementOverlay(packageName)
        }
    }
}

CPU usage between events: ~0%. Detection latency: under 100ms. The OS does the scheduling work, not your app.

The tradeoff

AccessibilityService requires a sensitive permission and needs to be explicitly granted by the user. It also carries a responsibility — you're reading every window change on the device. Design your event handler to be fast and stateless. Don't do network calls, don't block. Dispatch work elsewhere.

What I actually learned

The broader lesson isn't specific to Android. It's the same principle behind Kafka, webhooks, and database triggers — polling is a fallback for when you can't be notified. If the platform offers events, use them. Polling is just a slow, expensive approximation of listening.

Written by Basit Tijani. Find me on GitHub or LinkedIn.