Возможно ли получить ресурсы внутри статического контекстного блока?
Я хочу создать таблицу static Hash для преобразования строк в целые числа. Оговорка здесь в том, что я хочу использовать строки, которые я определил как ресурсы в нескольких списках в XML файлах.
Я могу написать это, используя только идентификаторы ресурсов:
public class MyActivity extends Activity {
private static Map<Integer, Integer> views = new HashMap<Integer, Integer>();
static {
views.put(R.string.full_text, MessageTable.VIEW_FULL);
views.put(R.string.only_text, MessageTable.VIEW_MSG);
views.put(R.string.tag_text, MessageTable.VIEW_TAGMSG);
}
Я не получаю ошибок, но мне действительно нужно сделать что-то вроде этого:
public class MyActivity extends Activity {
private static Map<String, Integer> views = new HashMap<String, Integer>();
static {
views.put(getResources().getString(R.string.full_text), MessageTable.VIEW_FULL);
views.put(getResources().getString(R.string.only_text), MessageTable.VIEW_MSG);
views.put(getResources().getString(R.string.tag_text), MessageTable.VIEW_TAGMSG);
}
который дает мне следующую ошибку в Eclipse:
Cannot make a static reference to the non-static method getResources() from the type ContextWrapper
Сообщение имеет смысл, но нет смысла в том, что ресурсы недоступны из статического блока, можно было бы подумать, что статические переменные были созданы пользователем для использования ресурсов.
Наверное, я могу заполнить таблицу Hash во время конструктора объекта, но это означало бы сделать это не в том месте.
Ответы
Ответ 1
getResources()
(сокращение от ~ MyActivity.this.getResources()
) требует объекта контекста, который в это время не инициализируется. Поскольку контекст доступен только после того, как вы нажали onCreate
, вы даже не можете сделать это во время построения MyActivity
.
Причина в том, что менеджер активности, который создает экземпляр класса MyActivity
, должен определить конфигурацию (ориентацию, размер экрана, язык...), прежде чем он узнает, какие ресурсы необходимо извлечь из xml. → Ресурсы не являются статическими и не могут быть доступны из статического контекста.
Итак, я думаю, что нет никаких способов делать эти операции в onCreate
или новее.
Изменить: Хотя вы, безусловно, можете обновить статический HashMap (или статический Context
) от onCreate
, я бы не рекомендовал это, так как вы можете иметь несколько экземпляров одного и того же Activity с возможными разными/изменяющимися конфигурациями. Также сохранение статического Context
- отличный способ создать Утечка памяти
Ответ 2
public Static Resources mResources;
public MyApplication extends Application
{
@Override
public void onCreate()
{
mResources = getResources();
}
}
Когда у вас есть статическая ссылка на ресурсы, вы можете ссылаться на нее в любом месте всего приложения. Тем не менее, я не уверен, что это приведет к утечке памяти или нет;
Ответ 3
Одна вещь, которую вы можете сделать, это создать класс Application
и зарегистрировать его в вашем AndroidManifest.xml. Затем переопределите метод onCreate и установите класс Application как статическую ссылку, а затем коснитесь класса Activity для запуска статического инициализатора. Класс Application
будет запущен, так как apk загружается в память, поэтому он всегда будет работать до любого Activity
.
Есть некоторые существенные недостатки. Наиболее очевидным я думаю, что если системный язык меняется, и вы добавили переводы к этим ресурсам; то у вас будут несогласованные строки, потому что приложение будет использовать значение по умолчанию/независимо от того, какой язык был при запуске приложения. На ресурсы String влияет система управления ресурсами Android, поэтому изменения в таких вещах, как ориентация, системный язык, размеры экрана, могут влиять на эти значения. Что причины, по которым Activities получают reset, когда
Короче, вам лучше использовать постоянные пары ключ-значение Strings для этого задания. Если вам нужно использовать строковые ресурсы, чтобы лучше выполнять переводы. Я загружаю их каждый раз, когда начинается действие. В противном случае вы рискуете утечками памяти и несогласованными строковыми переводами.
public MyApplication extends Application {
public static Context GlobalContext = null;
@Override
protected void onCreate() {
MyApplication.GlobalContext = this;
// Touch the activity class.
MyActivity activity = new MyActivity();
// Throw it away by not using it.
// invalidate handle to prevent GC leaks.
GlobalContext = null;
}
}
public class MyActivity extends Activity {
private static Map<String, Integer> views = new HashMap<String, Integer>();
static {
Context context = MyApplication.GlobalContext;
Resources res = context.getResources();
views.put(res.getString(R.string.full_text), MessageTable.VIEW_FULL);
views.put(res.getString(R.string.only_text), MessageTable.VIEW_MSG);
views.put(res.getString(R.string.tag_text), MessageTable.VIEW_TAGMSG);
}
}
Ответ 4
Вы всегда можете хранить статическую ссылку на ApplicationContext. Возможный способ описан здесь: Статический способ получить "Контекст" на Android?
Ответ 5
Я не знаю, что такое BEST. Но, например, в моем приложении у меня есть Singleton (так называемый GuiaUtil), который сохраняет мои текущие действия и контекст.
private static Map<String, Integer> views = new HashMap<String, Integer>();
static {
views.put(GuiaUtil.instance().getAppContext().getResources().getString(R.string.full_text), MessageTable.VIEW_FULL);
views.put(GuiaUtil.instance().getAppContext().getResources().getString(R.string.only_text), MessageTable.VIEW_MSG);
views.put(GuiaUtil.instance().getAppContext().getResources().getString(R.string.tag_text), MessageTable.VIEW_TAGMSG);
}