如何在onCreate()之前在静态string上使用getString()?

我想使用getString()从资源中获取一个string,在创build活动之前将其分配给一个String数组:

 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:string资源ID#0x7f0a000a

但是如果我把onCreate()放在里面:

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

我得到的string,但我不能把它分配给我以前定义的最终string。 如果我只在onCreate() getString()之前使用getString() ,我会得到静态错误消息。 如何在onCreate()之前为全局variables使用资源?

Solutions Collecting From Web of "如何在onCreate()之前在静态string上使用getString()?"

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

如果您在绑定应用程序资源之前需要这些string,则唯一实际的做法是将string直接放入代码中。 然而,“Android方式”将组织您的代码,所以初始化只需要在onCreate()期间(或之后)发生。 只需在onCreate()初始化string数组,不用担心字段是静态的还是最终的。

如果您不希望string数组与特定的活动关联,那么您可以inheritanceApplication并从应用程序类的onCreate()方法内的资源中读取数组。 (您还需要在清单中声明您的自定义应用程序类)。但是, 文档build议不要这种方法。 (因为数组是私有的,所以我怀疑它与单个活动密切相关,所以对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数据是在他的答案中提到的@JaiSoni中定义的<string-array>资源中)。成员字段再一次不能被声明为final

不,您不能在onCreate()之前使用资源。 您可以使用getResources()获取onCreate()的资源实例,您可以在其中获取所有的string。 另外,这些string已经通过在strings.xml定义来声明为静态的。

用于访问资源的伪代码,

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

以下是从XML中初始化android中的static finalvariables(如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(); } 

有关工作示例,请参阅AbstractApplicationPreferencesServiceSharedPreferences

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

  • 除了反对“Android的方式”(正如霍普在他的回答中所build议的),
  • 这使得testing有点困难。 这就是为什么对MyApplication.getContext()的调用被另一个方法包装的原因。 因为它是一个静态方法,所以在testing代码中覆盖它并不简单。 但是你可以使用Powermock这样的框架来达到这个目的。
  • 另外它有点容易发生NullPointerException 。 只要上下文为null (例如,在您的testing代码中),应用程序代码就会崩溃。 解决这个问题的一个方法就是在构造函数中进行初始化,在那里你可以对getContext()返回null (参见示例 )。

另一种方法是使用资源标识符(已经可用而不是资源本身)初始化静态数组。

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

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

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

无论你得到的getString(int resId)已经是你的应用程序常量。 为什么你必须保持在另一个final staticvariables。 你可以随时随地阅读,对吧?