Экспериментальный код.
Испробован вариант, когда загрузка изображений в фоне осуществляется только одним AsyncTask. Строится очередь и затем она последовательно обрабатывается. Несколько AsyncTask одновременно не запускаются!

Два варианта - два бага:
1. Для очереди использовался Map с контактом в качестве ключа. В процессе загрузки контакта его View мог несколько раз измениться. В результате отображались не все картинки, т.к. создавались лишние мифические View, которые никогда не отображались, но подменяли собой реальные View.
2. В очереди сохранялись все пары <Contact, View>. В этом случае происходит многократная перерисовка некоторых View. Например при старте появляется один View, в котором последовательно отрисовываются все контакты! Происходят и другие глюки.
Прилизано логирование.
Куда-то пропал match_parent для ListView! Вернул взад - и проблема с многократным вызовом getView ушла.
Но всё-равно этому варианту далеко до идеала: если открыть список и сразу его прокрутить, то по непонятным причинам на некоторых элементах сначала отображается фото другого контакта (который был выше), а затем уже прогружается правильное фото.
Да и некрасиво выглядит то, как фото появляются сразу, без плавного проявления (выглядит как-будто оно появляется "рывками").
С анимацией стало лучше, но глюк с отображением чужих фото при прокрутке остался!
Если в очереди на отрисовку соблюдать уникальность не только контактов, но и ViewHolder, то проблема с отображением чужих фото при прокрутке исчезает!