Android 如何在 onCreate() 之前在静态字符串上使用 getString()?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12506045/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 10:50:30  来源:igfitidea点击:

How to use getString() on static String before onCreate()?

androidstringstaticandroid-resources

提问by Andres

I am trying to use getString()to get an String from resources to assign it to an String array before my activity is created:

我正在尝试使用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)
};

When I use Resources.getSystem().getString(R.string.LCMeterMenu), Eclipse doesn't complain but I get an error at runtime:

当我使用 时Resources.getSystem().getString(R.string.LCMeterMenu),Eclipse 没有抱怨,但在运行时出现错误:

Caused by: android.content.res.Resources$NotFoundException: String Resource ID #0x7f0a000a

引起:android.content.res.Resources$NotFoundException:字符串资源 ID #0x7f0a000a

But if I put inside onCreate():

但如果我把里面onCreate()

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

I get the String but I can't assign it to the final String I defined before. If I use only getString()before onCreate()I get and static error message. How can I use resources before onCreate()for global variables?

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

回答by Ted Hopp

You cannot initialize a static finalfield from resources; the field needs to be initialized at the time the class is initialized and that happens before the application resources have been bound at run time. (By the way, the reason you cannot use Resources.getSystem()is that the Resourcesobject you obtain that way contains only system resources, not any application resources.)

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

If you need those strings available before the application resources are bound, the only practical thing to do is to put the strings into the code directly. However, the "Android way" would be to organize your code so initialization only needs to happen during (or after) onCreate(). Just initialize the string array in onCreate()and don't worry about making the fields static or final.

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

If you don't want the string array to be associated with a particular activity, then you can subclass Applicationand read the array from resources inside the application class's onCreate()method. (You also need to declare your custom application class in the manifest.) However, the docsrecommend against such an approach. (Since the array is private, I suspect that it is closely tied to a single activity anyway, so the use of an Applicationsubclass doesn't seem warranted.)

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

An alternative is to declare a singleton class for your array. The singleton accessor function then needs a Contextso it can retrieve the resources if necessary:

另一种方法是为数组声明一个单例类。单例访问器函数然后需要一个,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;
    }
}

(This assumes the string data are defined in a <string-array>resource like @JaiSoni suggested in his answer.) Once again, the member field cannot be declared final.

(这假设字符串数据是<string-array>在他的回答中建议的@JaiSoni 之类的资源中定义的。)再次,成员字段不能被声明final

回答by Lalit Poptani

No, you can't use Resources before onCreate(). You can get the instance of Resources in onCreate()by using getResources()where you can get all the Strings. Also the strings are already declared as static by defining them in the strings.xml.

不,您不能使用 Resources 之前onCreate()。您可以onCreate()通过使用getResources()where you can get all Strings 来获取Resources 的实例。此外,字符串已经通过在strings.xml.

Pseudo code for accessing the Resources,

用于访问资源的伪代码,

Resources res = getResources();
String app_name = res.getString(R.string.app_name);

回答by bompf

Another approach could be to initialize the static array with resource identifiers (which are already available as opposed to the resources themselves).

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

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

This way, you can defer the loading of resources to when they are actually available:

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

String s = getResources().getString(MenuNames[i]);

回答by schnatterer

The following is a working approach to initialize static finalvariables in android from XML, such as strings.xml.

以下是一种static final从 XML初始化android 中变量的工作方法,例如strings.xml.

  1. Subclass application and provide a "static context"
  2. Register the application class in manifest
  3. Use the static context to initialize your constants
  1. 子类应用程序并提供“静态上下文”
  2. 在清单中注册应用程序类
  3. 使用静态上下文初始化常量

1.MyApplication.java

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

2.AndroidManifest.xml

<application
    android:name=".android.application.MyApplication"
    <!-- ... -->
</application>

3.Your application code, e.g. Activity

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();
}

For working examples refer to AbstractApplicationand PreferencesServiceSharedPreferences.

有关工作示例,请参阅AbstractApplicationPreferencesServiceSharedPreferences

Note that this approach also has its downsides:

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

  • Apart from being opposed to the "Android way" (as @Ted Hopp suggested in his answer),
  • it makes testing a bit difficult. That is why the call to MyApplication.getContext()is wrapped in another method. As it is a static method, overriding it in testing code is not simple. But you could use a framework such as Powermockfor this purpose.
  • In addition it is a bit prone to NullPointerExceptions. As soon as the context is null(e.g. in your testing code) the application code crashes. One option to overcome this, is to do the initialization in a constructor, where you could react to getContext()returning null(see example).
  • 除了反对“Android方式”(正如@Ted Hopp在他的回答中所建议的那样),
  • 它使测试有点困难。这就是为什么调用MyApplication.getContext()被包装在另一个方法中的原因。由于它是一个静态方法,因此在测试代码中覆盖它并不简单。但是您可以为此目的使用诸如Powermock 之类的框架。
  • 此外,它有点容易出现NullPointerExceptions。一旦上下文null(例如在您的测试代码中),应用程序代码就会崩溃。克服这个问题的一种选择是在构造函数中进行初始化,您可以在其中对getContext()返回做出反应null(参见示例)。

回答by midhunhk

Whatever you get by the getString(int resId)will already be a constant for your application. Why do you have to keep it in another final staticvariable. You can read it like that whenever you want, right?

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