А вот такая тема. Допустим, колбасим под android и захотелось нам, что б в нашем
TextView ссылки были нажимабельными. Нормальное такое желание. Что б, если клик по телефону - запускалась звонилка, а если по e-mail - открывался почтовый клиент. Сказано - сделано! Гуглим и первой же ссылкой находим какой-нибудь
вопрос-ответ на StackOverflow, говорящий нам сделать что-то подобное:
TextView someTextView = ...
someTextView.setMovementMethod(LinkMovementMethod.getInstance());Запиливаем, и о-ба-на! Работает! Даём потестить тестерам - работает! Огонь! Релизим. А после релиза начинаем ловить падения :)
А дело вот в чём. Понятно, что открытия всех этих звонилок, e-mail клиентов и прочих браузеров происходят через запуск активности, который на android можно сделать многими способами.
LinkMovementMethod делает это (по крайне мере на момент версии робота 5.0) через вызов
onClick у
ClickableSpan, который в свою очередь, будучи на самом деле
URLSpan'ом, зовёт банальный
Context.startActivity, документация на который говорит, что если активность под
Intent не будет найдена, то будет выброшено исключение
ActivityNotFoundException! А что у нас есть? Правильно, «рутованые» телефоны без e-mail клиентов, китайские планшеты без звонилок и прочие весёлые устройства.
Лечится дело не очень красиво, зато наверняка:
наследуемся от LinkMovementMethod и заворачиваем все его методы в try {} catch (Throwable e) {}.
Можно, конечно, попробовать замутить свой URLSpan, но это отдельная тема, про которую сейчас лениво писать.
А интересность тут в том, что этот самое злосчастное исключение бросается в стеке вызовов к которому наш код, обычно, мало отношения имеет. То есть use case вообще не рассчитан на обработку пользовательским кодом и вообще никакой не use case, а банальный ляп товарищей из гугла. Естественно, цветёт и пахнет по сей день в свежайшей версии android.