Как использовать 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.content.res.Resources$NotFoundException: идентификатор строкового ресурса #0x7f0a000a

Но если я поставлю внутрь onCreate():

Log.i("StringR", "String: " + getString(R.string.LCMeterMenu));

Я получаю строку, но не могу назначить ее окончательной строке, которую я определил ранее. Если я использую только getString() перед onCreate(), я получаю статическое сообщение об ошибке. Как я могу использовать ресурсы до onCreate() для глобальных переменных?


person Andres    schedule 20.09.2012    source источник
comment
вы попробовали String getResources().getString(R.string.LCMeterMenu); вместо Resources.getSystem().getString(R.string.LCMeterMenu)   -  person ρяσѕρєя K    schedule 20.09.2012
comment
Почему вы хотите объявить массив окончательным. Почему вы не можете объявить массив как частный статический и инициализировать массив в onCreate().   -  person knvarma    schedule 20.09.2012
comment
Поскольку массив не будет меняться во время выполнения Activity, не лучше ли использовать final ?   -  person Andres    schedule 20.09.2012
comment
@Andres, если вы хотите, чтобы он был окончательным, вы можете использовать его таким образом. окончательная строка [] sa = новая строка [n]; поскольку вы хотите заполнить массив строками ресурсов, которые вы знаете, значение n. а потом в onCreate обнови вроде. са[0] = ресурсная строка1; и т. д., помните, что вы можете изменить значения или сказать, что заполните массив, когда захотите, даже если он объявлен как окончательный.   -  person Archie.bpgc    schedule 20.09.2012


Ответы (5)


Вы не можете инициализировать поле static final из ресурсов; поле должно быть инициализировано во время инициализации класса, и это происходит до того, как ресурсы приложения будут привязаны во время выполнения. (Кстати, причина, по которой вы не можете использовать Resources.getSystem(), заключается в том, что объект Resources, который вы получаете таким образом, содержит только системные ресурсы, а не какие-либо ресурсы приложения.)

Если вам нужны эти строки, доступные до того, как ресурсы приложения будут привязаны, единственное практическое решение — поместить строки непосредственно в код. Однако «способ Android» будет заключаться в организации вашего кода, поэтому инициализация должна происходить только во время (или после) 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 в своем ответе.) Еще раз, поле члена не может быть объявлено final.

person Ted Hopp    schedule 20.09.2012

Нет, вы не можете использовать Ресурсы до onCreate(). Вы можете получить экземпляр ресурсов в onCreate(), используя getResources(), где вы можете получить все строки. Кроме того, строки уже объявлены как статические, определив их в файле strings.xml.

Псевдокод для доступа к Ресурсам,

Resources res = getResources();
String app_name = res.getString(R.string.app_name);
person Lalit Poptani    schedule 20.09.2012
comment
Если я использую getResources().getString(), я получаю: Не могу сделать статическую ссылку на нестатический метод getResources() из типа ContextWrapper - person Andres; 20.09.2012
comment
Да, я попробовал этот способ, и он работает, но я должен исключить ключевое слово static. Думаю, мне придется исключить static или final, насколько я вижу, другого пути нет. - person Andres; 20.09.2012

Другой подход может заключаться в инициализации статического массива идентификаторами ресурсов (которые уже доступны, а не сами ресурсы).

private static final int[] MenuNames = {
    R.string.LCMeterMenu,
    R.string.FrecMenu,
    ...
};

Таким образом, вы можете отложить загрузку ресурсов до того момента, когда они действительно будут доступны:

String s = getResources().getString(MenuNames[i]);
person bompf    schedule 22.07.2015

Ниже приведен рабочий подход к инициализации переменных static final в android из XML, например strings.xml.

  1. Приложение подкласса и предоставить «статический контекст»
  2. Зарегистрируйте класс приложения в манифесте
  3. Используйте статический контекст для инициализации ваших констант

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. Код вашего приложения, например. Мероприятия

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.
  • Кроме того, он немного склонен к NullPointerExceptions. Как только контекст становится null (например, в вашем тестовом коде), код приложения дает сбой. Один из способов преодолеть это — выполнить инициализацию в конструкторе, где вы могли бы реагировать на getContext()returning null (см. /schnatterer/nusic/logic/impl/PreferencesServiceSharedPreferences.java" rel="nofollow noreferrer">пример).
person schnatterer    schedule 19.10.2014

Все, что вы получите с помощью getString(int resId), уже будет константой для вашего приложения. Почему вы должны хранить его в другой переменной final static. Ты можешь читать это так, когда захочешь, верно?

person midhunhk    schedule 20.09.2012
comment
Разве это не правильный способ использования моей строки, если она не изменится во время выполнения моей активности? Лучшая производительность также? Я новичок в Java, поэтому я учусь :) - person Andres; 20.09.2012
comment
Если у вас много экземпляров, в которых вы будете вызывать метод getResources().getString(), выполните инициализацию в методе onCreate() и сделайте вашу переменную статической. Это мое мнение. - person midhunhk; 20.09.2012
comment
Почему вы должны хранить его в другой финальной статической переменной. Потому что использование static final STRING_CONSTANT дает более читаемый код. Например: tv.setText(STRING_CONSTANT) против tv.setText(getString(R.string.string_constant)) - person Jose_GD; 07.06.2013