【问题标题】:Is it possible to get resources inside a static context block?是否可以在静态上下文块中获取资源?
【发布时间】:2012-04-29 00:57:15
【问题描述】:

我想创建一个静态哈希表来将字符串转换为整数。这里需要注意的是,我想使用 strings 我在 XML 文件 的几个列表中定义为 resources

我可以写这个,只使用资源 ID:

public class MyActivity extends Activity {

private static Map<Integer, Integer> views = new HashMap<Integer, Integer>();
static {
    views.put(R.string.full_text, MessageTable.VIEW_FULL);
    views.put(R.string.only_text, MessageTable.VIEW_MSG);
    views.put(R.string.tag_text, MessageTable.VIEW_TAGMSG);
}

我没有收到任何错误,但我真正需要做的是这样的事情:

public class MyActivity extends Activity {

private static Map<String, Integer> views = new HashMap<String, Integer>();
static {
    views.put(getResources().getString(R.string.full_text), MessageTable.VIEW_FULL);
    views.put(getResources().getString(R.string.only_text), MessageTable.VIEW_MSG);
    views.put(getResources().getString(R.string.tag_text), MessageTable.VIEW_TAGMSG);
}

这给了我在 Eclipse 中的以下错误:

Cannot make a static reference to the non-static method getResources() from the type ContextWrapper

该消息是有道理的,但没有意义的是静态块无法访问资源,人们会认为静态变量是自定义创建的以利用资源。
我想我可以在对象构造函数期间填充哈希表,但这意味着在错误的地方进行。

【问题讨论】:

  • 为什么要将所有内容加载到哈希映射中?当您非静态需要它时,仅引用资源并将其加载到字符串中不是很好吗?我想我不完全了解应用程序。

标签: android resources static


【解决方案1】:

getResources()(简称 ~MyActivity.this.getResources())需要一个当时未初始化的上下文对象。由于上下文仅在您点击onCreate 后才可用,您甚至无法在MyActivity 的构建时间执行此操作。

原因是实例化MyActivity 类的活动管理器必须先确定配置(方向、屏幕大小、语言……),然后才能知道必须从 xml 中提取哪些资源。 -> 资源不是静态的,不能从静态上下文中访问。

所以我想在onCreate 或更高版本中进行这些操作是没有办法的。

编辑:虽然您当然可以从 onCreate 更新静态 HashMap(或静态 Context),但我不建议您这样做,因为您可以拥有相同 Activity 的多个实例,但配置可能不同/更改。存储静态Context 也是创建Memory Leak 的好方法

【讨论】:

  • 我认为资源是应用程序中最静态的元素。否则你怎么解释访问 R.string.stringname 很好?我明白你为什么会出现错误的解释,我希望有人知道绕过字符串的方法。
  • 那些R.whatever 的东西是由android 的构建工具在编译时创建的。它们只是引用您的资源的int id。为该 id 检索的实际内容是根据配置确定的。这是必需的,因为您可以/应该对同一个 id 有多个定义,例如res/values/strings.xmlres/values-es/strings.xmlres/values-land-mdpi/strings.xml中的字符串
  • 保留应用上下文不会导致内存泄漏。但是,保留特定的上下文可以。
  • @MartinAsenov 好的,保留应用程序上下文非常安全,但如果使用不当可能会导致泄漏。来自文档:“但是,如果您忘记取消注册、取消绑定等,在其他地方使用 ApplicationContext 很容易导致严重的泄漏。”
  • 如果字符串不可翻译,由于系统资源的原因,它们可以以静态方式访问,详情请参阅this SO response。这被 AOSP 用来通过覆盖覆盖默认配置,例如搜索 config_wifi_tether_enable
【解决方案2】:
public Static Resources mResources;
public MyApplication extends Application
{
     @Override
     public void onCreate()
     {
           mResources = getResources();
     }

}

获得对资源的静态引用后,您可以在整个应用程序的任何位置引用它。但是我不确定这是否会导致内存泄漏;

【讨论】:

    【解决方案3】:

    您可以做的一件事是创建一个Application 类并将其注册到您的AndroidManifest.xml 中。然后重写 onCreate 方法并将 Application 类设置为静态引用,然后触摸 Activity 类以运行静态初始化程序。 Application 类将在 apk 加载到内存时运行,因此它将始终在任何 Activity 之前运行。

    这有一些明显的缺点。我想到的最明显的一个是系统语言是否发生了变化,并且您已经为这些资源添加了翻译;那么您将有不一致的字符串,因为应用程序将使用默认/启动应用程序时的任何语言。字符串资源受 Android 资源管理系统的影响,因此方向、系统语言、屏幕尺寸等内容的更改会影响这些值。这就是当

    时活动被重置的原因

    简而言之,你最好使用常量字符串键值对来完成这项工作。如果您需要使用字符串资源,以便更好地处理翻译。每次活动开始时我都会加载它们。否则,您将面临内存泄漏和不一致的字符串翻译的风险。

    public MyApplication extends Application {
    
      public static Context GlobalContext = null;
    
      @Override
      protected void onCreate() {
        MyApplication.GlobalContext = this;
    
        // Touch the activity class.
        MyActivity activity = new MyActivity();
        // Throw it away by not using it.
    
        // invalidate handle to prevent GC leaks.
        GlobalContext = null;
      }
    }
    
    public class MyActivity extends Activity {
      private static Map<String, Integer> views = new HashMap<String, Integer>();
    
      static {
        Context context = MyApplication.GlobalContext;
        Resources res = context.getResources();
        views.put(res.getString(R.string.full_text), MessageTable.VIEW_FULL);
        views.put(res.getString(R.string.only_text), MessageTable.VIEW_MSG);
        views.put(res.getString(R.string.tag_text), MessageTable.VIEW_TAGMSG);
      }
    }
    

    【讨论】:

    • 我明白了。情况不是我所希望的,但我将不得不处理手头的事情。谢谢
    【解决方案4】:

    您始终可以保留对 ApplicationContext 的静态引用。这里描述了一种可能的方式:Static way to get 'Context' on Android?

    【讨论】:

    • 同上,在您的链接中,上下文仅在 onCreate() 期间设置。我需要资源来立即构建地图,可能在 onCreate() 之前。
    • 但是你让我想到了,我实际上有一个相关的类似问题,你能在 XML 中定义一个地图吗?如果这是可能的,那么我肯定可以在 XML 文件中使用我的资源。我想我会把它作为一个新问题发布,因为它应该有自己的帖子。
    【解决方案5】:

    我不知道什么是最好的方法,但是,例如,在我的应用程序中,我有一个 Singleton(称为 GuiaUtil),它可以保留我当前的 Activity 和 Context。

    private static Map<String, Integer> views = new HashMap<String, Integer>();
    static {
    views.put(GuiaUtil.instance().getAppContext().getResources().getString(R.string.full_text), MessageTable.VIEW_FULL);
    views.put(GuiaUtil.instance().getAppContext().getResources().getString(R.string.only_text), MessageTable.VIEW_MSG);
    views.put(GuiaUtil.instance().getAppContext().getResources().getString(R.string.tag_text), MessageTable.VIEW_TAGMSG);
    }
    

    【讨论】:

    • 这是一个与您的代码相似且实际有效的代码吗?因为在我看来你应该得到 getAppContext() 的错误,因为执行此静态块时可能尚未设置上下文。
    • 如果你想把它放在你的第一个活动中,那么它可能不会工作,因为你还没有设置单例......正如我所说,这显然不是最好的方法这,但这是一个开始。无论如何,您可以在“onCreate”上创建静态 HashMap,在实例化之前检查它是否不为空。
    猜你喜欢
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 2011-06-11
    • 1970-01-01
    • 2012-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多