19

我正在尝试在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:字符串资源 ID #0x7f0a000a

但如果我把里面onCreate()

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

我得到了字符串,但我无法将它分配给我之前定义的最终字符串。如果我只getString()onCreate()收到静态错误消息之前使用。以前如何将资源onCreate()用于全局变量?

4

5 回答 5

28

您不能static final从资源中初始化字段;该字段需要在初始化类时初始化,并且在运行时绑定应用程序资源之前发生。(顺便说一句,您无法使用的原因Resources.getSystem()是您通过这种方式获得的Resources对象仅包含系统资源,而不包含任何应用程序资源。)

如果在绑定应用程序资源之前需要这些字符串可用,唯一可行的做法是将字符串直接放入代码中。但是,“Android 方式”是组织您的代码,因此初始化只需要在 期间(或之后)进行onCreate()。只需在其中初始化字符串数组,onCreate()不必担心将字段设为静态或最终字段。

如果您不希望字符串数组与特定活动相关联,那么您可以从应用程序类方法Application内的资源中子类化并读取该数组。onCreate()(您还需要在清单中声明您的自定义应用程序类。)但是,文档建议不要使用这种方法。(由于数组是私有的,我怀疑它无论如何都与单个活动密切相关,因此Application似乎没有必要使用子类。)

另一种方法是为您的数组声明一个单例类。然后,单例访问器函数需要 aContext以便在必要时检索资源:

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

于 2012-09-20T06:48:35.413 回答
4

不,您不能使用 Resources before onCreate()onCreate()您可以通过使用getResources()可以获取所有字符串的位置来获取资源的实例。此外,字符串已经通过在strings.xml.

用于访问资源的伪代码,

Resources res = getResources();
String app_name = res.getString(R.string.app_name);
于 2012-09-20T04:33:37.580 回答
3

另一种方法可能是使用资源标识符初始化静态数组(与资源本身相反,这些标识符已经可用)。

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

这样,您可以将资源的加载推迟到它们实际可用的时候:

String s = getResources().getString(MenuNames[i]);
于 2015-07-22T15:46:04.737 回答
1

以下是static final从 XML 初始化 android 中的变量的工作方法,例如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.您的应用程序代码,例如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();
}

有关工作示例,请参阅AbstractApplicationPreferencesServiceSharedPreferences

请注意,这种方法也有其缺点:

  • 除了反对“Android方式”(正如@Ted Hopp在他的回答中建议的那样),
  • 它使测试有点困难。这就是为什么调用MyApplication.getContext()被包装在另一个方法中的原因。由于它是一个静态方法,因此在测试代码中覆盖它并不简单。但是您可以为此目的使用Powermock等框架。
  • 另外它有点容易出现NullPointerExceptions。一旦上下文null出现(例如在您的测试代码中),应用程序代码就会崩溃。克服这个问题的一种选择是在构造函数中进行初始化,您可以在其中对getContext()返回做出反应null(参见示例)。
于 2014-10-19T15:10:25.320 回答
0

无论您得到什么,getString(int resId)都将成为您的应用程序的常数。为什么必须将其保存在另一个final static变量中。您可以随时阅读它,对吗?

于 2012-09-20T04:34:55.140 回答