Как стать автором
Обновить

Комментарии 18

Пост ни о чем. Читайте доки, чтобы не хотеть вызывать статические контексты.
«которое заключается в создании класса статичного Application'а.» — синглтон что ли?
Строго говоря, это не совсем singleton, т.к. теоретически он может быть проинстанцирован несколько раз. Я даже не знаю гарантированно ли конструктор android.app.Application будет вызван один раз — доки молчат.
Конструктор будет вызван 1 раз, в приложении, тогда же когда и onCreate() где можно делать что-то, но не связанное с UI, так как UI в этот момент еще нету. Лучше делать что-то очень быстро иначе будут неприятные задержки открытия приложения.

Это не статический класс! Так к нему всегда есть доступ из других Activity/Context #getApplicationContext() instanceof Application.

В общем спецификация абсолютно не гарантирует, что это static Singleton. Поэтому все настройки, ссылки сервисы и инициализации действительно хранить лучше в нем!
Конструктор таки будет вызван один раз. Другое дело, что этот инстанс все равно нельзя будет использовать (для доступа к методам Context) до тех пор пока не будет вызван метод onCreate активити.
Может быть да, а может быть и нет. Мне не нравится, когда в коде пестрит R.class.
Кстати, есть конкретный пример, когда можно использовать данный подход: есть андроид приложение, есть сторонняя библиотека. Эта самая библиотека может, например, выбрасывать exception (который, кстати, может вообще не знать, что он в контексте андроида), хранящий в себе некий идентификационный номер сообщения. Приложение должно как-то локализовать (в смысле — перевести) данное сообщение и вывести на экран. Первый вариант, который приходит в голову — switch на все возможные варианты:
if ( e.getMessageId().equals("msg_001") ) {
   context.getString(R.strings.msg_001);
} else if ( ... ) {
   // and other dozens
}
Мой вариант предлагает
TranslationsCache.instance.getCaption(e.getMessageId());
Красиво? Мне кажется — да.
Мне вот не понятно — за что минусы. Я описал конкретный случай, когда использвание R.class не очень удобно.
И я не говорю, что так нужно делать всегда. Я говорю, что есть разные способы решения поставленной задачи. Чтобы это понять достаточно было зайти в мой репозитарий на github и посмотреть реальный код.

Кстати, программисты андроид платформы — тоже не боги, достаточно взглянуть на их issue tracker. Моё мнение (как и мнение некоторых моих коллег) такое, что R.class — вообще довольно спорная штука.
ну а почему бы для вашего случая не хранить в хэшмапе id сообщения об ошибке и id строки в R файле? тогда будет как то так:
int errStringId = errorsMap.get(e.getMessageId());
context.getString(errStringId);


Как по мне, так приведенное вами решение — костыль с большой буквы
Вы предлагаете сделать следующее:
Map<String, Integer> stringsIdsByMessageIds;
где ключ — внешний идентификатор сообщения, значение — внутренний идентификатор (значение поля в R.class).
Как вы будете инициализировать данный Map? Отвечу за вас — вы будете писать что-то наподобие следующего:
map.put("msg_01", R.string.msg_01);
map.put("msg_02", R.string.msg_02);
// and so on
Какие минусы:
1. При добавлении нового сообщения вам нужно будет не забыть добавить строчку инициализации Map'а
2. При числе сообщений over 9000 вам придётся иметь over 9000 строк инициализации Map.

Моё решение — динамическое и оно избавляет нас от минусов привидённых выше.
именно
но вытягивание большого количества строк с помощью рефлексии и их постоянное хранение в памяти может оказаться затратным по ресурсам. к тому же, если я правильно понимаю, метод initCaptions проходит в цикле по всем идентификаторам ресурсов, коих обычно немало.
приведенный вами случай очень специфичен. обычно достаточно хранить строки по локализованным папкам (вроде values-fr) и вытягивать через context
1. initCaptions() проходит только по R.string
2. Ничего затратного тут нет — что-то мне подсказывает, что вытягивание статических полей класса их значений — это очень быстрая операция (Кстати, а как вы думаете как реализовано связывание strings.xml и R.string внутри андроид ядра? Мне кажется тоже с использованием такого подхода).
3. Хранение тоже довольно дёшево — там же просто строки
4. Да, случай специфичен, но иногда нужна знать и использовать его.
Мне в свое время помогло решение кэшировать всю информацию, выставить политику обновлений по таймстампу и использовать where-условия для извлечения посредством использования orm данных с нужной локализацией. Просто и со вкусом. А, простите, если у Вас не динамические ресурсы, то проще использовать квалификаторы директорий.
ну да, как-то сложно все. С переводами и статическими классами явно решение не из удачных, на мой взгляд.
Если вам нужен контекст в столь многих местах, что надоедает его туда-сюда таскать, есть смысл задуматься об архитектуре приложения.
абсолютно с вами согласен. если хочется запихнуть контекст в синглтон, то это явный признак того, что что-то не так сделано. а пихать контекст в аппликейшен — это какое-то уже совсем наколенное решение. тем более нет уверенности, что он не разрушится (даже если это конекст приложения)
бред. половина советов — как нельзя делать. устроить из android.app.Application помойку, а из кода приложения макароны которые не разобрать, не протестировать. велосипед с ресурсами говорит только о незнании о Resources.getIdentifier()
Спасибо за наводку, про Resources.getIdentifier(), не знал — посмотрю. Насчёт макарон, пожалуйста, поподробнее — есть реальный проект, где всё приведённое выше использовалось. Можете ткнуть в куски кода, которые по вашему мнению написаны не очень хорошо — обсудим. Ссылка на проект — в конце статьи.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации