Как использовать getString () в статической строке перед onCreate ()?
Я пытаюсь использовать getString()
чтобы получить строку из ресурсов, чтобы назначить ее массиву строк до создания моей активности:
private static final String[] MenuNames = {
Resources.getSystem().getString(R.string.LCMeterMenu),
Resources.getSystem().getString(R.string.FrecMenu),
Resources.getSystem().getString(R.string.LogicAnalyzerMenu),
"Prueba con achartengine",
Resources.getSystem().getString(R.string.BrazoMenu)
};
когда я использую Resources.getSystem().getString(R.string.LCMeterMenu)
, Eclipse не жалуется, но я получаю ошибку во время выполнения:
вызвано: android.содержание.res.Resources$NotFoundException: строка ID ресурса #0x7f0a000a
но если я положу внутрь onCreate()
:
Log.i("StringR", "String: " + getString(R.string.LCMeterMenu));
Я получаю строку, но я не могу назначить ее в финал Строка, которую я определил раньше. Если я использую только getString()
до onCreate()
Я получаю и статическое сообщение об ошибке. Как я могу использовать ресурсы до onCreate()
глобальные переменные?
5 ответов
вы не можете инициализировать static final
поле из ресурсов; поле должно быть инициализировано во время инициализации класса, и это происходит до привязки ресурсов приложения во время выполнения. (Кстати, причина, по которой вы не можете использовать Resources.getSystem()
это Resources
объект, который вы получаете таким образом, содержит только системные ресурсы, а не ресурсы приложения.)
Если вам нужны эти строки, доступные до привязки ресурсов приложения, единственное практическое что нужно сделать, так это поместить строки непосредственно в код. Тем не менее," Android way " будет организовывать ваш код, поэтому инициализация должна произойти только во время (или после) onCreate()
. Просто инициализируйте массив строк в onCreate()
и не беспокойтесь о том, чтобы сделать поля статическими или окончательными.
если вы не хотите, чтобы массив строк был связан с определенным действием, то вы можете подкласс Application
и прочитайте массив из ресурсов внутри класса приложения onCreate()
метод. (Необходимо также объявить пользовательский класс приложения в манифесте.) Однако, документы рекомендую против такого подхода. (Поскольку массив является частным, я подозреваю, что он тесно связан с одним действием в любом случае, поэтому использование Application
подкласс не кажется оправданным.)
альтернативой является объявление одноэлементного класса для вашего массива. Функция одноэлементного доступа затем нуждается в Context
таким образом, он может получить ресурсы, если необходимо:
public class StringArray {
private static String[] theArray;
public static String[] getArray(Context context) {
if (theArray == null) {
theArray = context.getResources().getStringArray(R.array.my_strings);
}
return theArray;
}
}
(это предполагает, что строковые данные определены в <string-array>
ресурс, как @JaiSoni предложил в своем ответе.) Еще раз, поле member не может быть объявлено final
.
нет, вы не можете использовать ресурсы перед onCreate()
. Вы можете получить экземпляр ресурсов в onCreate()
С помощью getResources()
где вы можете получить все строки. Кроме того, строки уже объявлены как статические, определив их в strings.xml
.
псевдо-код для доступа к ресурсам,
Resources res = getResources();
String app_name = res.getString(R.string.app_name);
другим подходом может быть инициализация статического массива идентификаторами ресурсов (которые уже доступны, в отличие от самих ресурсов).
private static final int[] MenuNames = {
R.string.LCMeterMenu,
R.string.FrecMenu,
...
};
таким образом, вы можете отложить загрузку ресурсов, когда они действительно доступны:
String s = getResources().getString(MenuNames[i]);
ниже приведен рабочий подход для инициализации static final
переменные в android из XML, такие как strings.xml
.
- подкласс приложения и обеспечить "статический контекст"
- зарегистрировать класс приложения в manifest
- используйте статический контекст для инициализации констант
1. MyApplication.java
public abstract class MyApplication extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
/**
* Returns a "static" application context. Don't try to create dialogs on
* this, it's not gonna work!
*
* @return
*/
public static Context getContext() {
return context;
}
}
2. AndroidManifest.xml
<application
android:name=".android.application.MyApplication"
<!-- ... -->
</application>
3. Ваш код приложения, например Activity
private static final String[] MenuNames = {
getContext().getString(R.string.LCMeterMenu),
getContext().getString(R.string.FrecMenu),
getContext().getString(R.string.LogicAnalyzerMenu),
"Prueba con achartengine",
getContext().getString(R.string.BrazoMenu)
};
protected static Context getContext() {
return MyApplication.getContext();
}
для рабочих примеров см. AbstractApplication
и PreferencesServiceSharedPreferences
.
обратите внимание, что этот подход также имеет свои минусы:
- помимо того, что он противостоит "пути Android" (как предложил @Ted Hopp в ответ),
- это делает тестирование намного сложнее. Вот почему призыв к
MyApplication.getContext()
обернут в другой метод. Поскольку это статический метод, переопределить его в тестовом коде непросто. Но вы можете использовать такую структуру, как Powermock для этой цели. - кроме того, он немного склонен к
NullPointerException
s. Как только контекстnull
(например, в вашем тестовом коде) код приложения аварийно завершает работу. Одним из вариантов преодоления этого является инициализация в конструкторе, где вы можете реагировать наgetContext()
возвращениеnull
(см. пример).
что вы получаете от getString(int resId)
уже будет константой для вашего приложения. Почему вы должны держать его в другой final static
переменной. Ты можешь читать это так, когда захочешь, верно?