The reason you can't detach the listener is because you're already in the route
event. By that point all the listeners have been marshalled together and queued for execution.
Why not instead take the listener out of the equation beforehand?
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$events = $app->getEventManager();
$shared = $events->getSharedManager();
$services = $app->getServiceManager();
$routeListener = $services->get('RouteListener');
$routeListener->detach($events);
$shared->attach('Zend\Mvc\Application', MvcEvent::EVENT_ROUTE, array($this, 'onRoute'), 100);
}