Самого долго мучали подобные вопросы (некоторые даже до сих пор).
В Android-е все асинхронные механизмы базируются на Thread. Однако крайне желательно (все практики об этом говорят) использовать более высокоуровневые "родные" Android-механизмы.
И все же при всем желании, избежать столкновения с java-concurrency не получится.
Примеры из своей практики:
Service - который все время в работе (например, стрим-видео, vpn и тд) и еще и управлять этим процессом налету надо(приостановить/прервать/продолжить итд)
При внимательном изучении ServiceHandler - ты поймешь, что это неподходящее решение в данном случае. Тут только от Service наследоваться - ну и дальше по цепочке -
- в главном потоке (onStartCommand) - нельзя, нужен Thread, а если еще одна команда придет - то не плодить же потоки - уж лучше Executor и тд. и тп
Далее - Content Provider, который ходит не в базу, а в сеть(тут меня ждал большой облом)
Оказывается NetworkOnMainThreadException - это не только про сеть в активити,
это вообще про сеть в главном(пусть даже не UI-ном треде) - поэтому в любом случае(хоть Service, хоть Content Provider и тд) - ты должен отдупляться от главного потока (по крайнее мере для запросов в сеть)
Касаемо Content Provider - пойти в сеть прям в методе(qeury/openFile/и тд) нельзя (NetworkOnMainThreadException) но и дождаться респонса надо прям тут (синхронно)- вот те и пляски Callable's, Future's
Так что при всем твоем (и моем тоже) желании поступать высокоуровнево, без велосипедов - увы не всегда возможно