如何从静态上下文中获取资源内容?

los*_*aby 160 java static android const android-resources

我想xml在我做很多其他事情之前从文件中读取字符串,比如setText在窗口小部件上做什么,所以如果没有要调用的活动对象,我怎么能这样做getResources()呢?

Cri*_*ian 367

  1. Application例如,创建一个子类public class App extends Application {
  2. 将标记的android:name属性设置为指向新类,例如<application>AndroidManifest.xmlandroid:name=".App"
  3. onCreate()app实例的方法中,将上下文(例如this)保存到名为的静态字段,mContext并创建一个返回此字段的静态方法,例如getContext():

它应该是这样的:

public class App extends Application{

    private static Context mContext;

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = this;
    }

    public static Context getContext(){
        return mContext;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以使用:App.getContext()每当你想获得一个上下文,然后getResources()(或App.getContext().getResources()).

  • 为了避免内存泄漏,最好将Context存储在WeakReference中:private static WeakReference <Context> mContext; public static Context getContext(){return mContext.get(); 当应用程序崩溃并且您无法将静态上下文设置为null(WeakReference可以被垃圾收集)时,这应该会有所帮助. (23认同)
  • 我不能不认为这是一个'黑客'.Altough我正在使用它(顺便说一句,感谢你提供这个解决方案,因为我正要将本地化外化)我得到了这种不好的感觉,就像这是错误的. (16认同)
  • 文档说"通常没有必要继承应用程序.在大多数情况下,静态单例可以以更模块化的方式提供相同的功能.如果您的单例需要全局上下文(例如注册广播接收器),则要检索的函数可以给它一个Context,它在第一次构造单例时在内部使用Context.getApplicationContext()." 〜HTTP://developer.android.com/reference/android/app/Application.html (12认同)
  • 应用程序的实例不是动态值,怎么这么@Gangnus?无论如何 - 我发现在Android上依赖静态的困难方式只不过是头痛."现在你看到它了,现在你没有看到它" (9认同)
  • 比仅仅将Context作为应用程序中每个静态方法的第一个参数传递更好还是更差?前者感觉很讨厌,但后者是不必要的重复. (8认同)
  • @MiloRambaldi我在onCreate()中使用此代码:mContext = new WeakReference <Context>(this); 希望它能帮到你. (5认同)
  • 怎么会有内存泄漏?AppContext是App对象. (3认同)
  • @Bostone - 它们不是动态值.我们正在谈论通过资源设置静态常量.相反,我认为,这种方式的问题是我们不能将这些常量用作整个应用程序类的静态,即使它们对整个应用程序类都是静态的.但99%的问题都可以通过这种方式解决.+1来Cristian! (2认同)
  • 哦,是的,实际上,通过实现它们是动态的,或者让我们更好地说,实例常量.应用程序的实例.但相对的活动,当然,要的setText和等,如*在*的问题,他们可以静态地设置 - 即以下这个答案你可以让他们为常数属于Activity类的后裔.2.静态变量在Android中运行正常.问题是如果你想使用一些资源作为Application静态变量/常量的值,那是不可能的.你只有两个部分解决方案,在这里给出答案. (2认同)
  • 静态应用程序(或其上下文)实例的泄漏是不可能的。应用程序对象就是应用程序,如果应用程序关闭,则不再有任何引用。 (2认同)

Gan*_*nus 98

使用

Resources.getSystem().getString(android.R.string.cancel)
Run Code Online (Sandbox Code Playgroud)

您可以在应用程序的任何地方使用它们,即使在静态常量声明中也是如此!但仅限系统资源!

  • 你必须要小心.不要尝试使用此方法查找您的应用资源.阅读细则:返回一个全局共享资源对象,该对象仅提供对系统资源的访问(无应用程序资源),并且未针对当前屏幕进行配置(不能使用维度单位,不会根据方向更改等). (17认同)
  • @ DroidIn.net引用:"但仅限系统资源!".我知道/*叹气/* (3认同)
  • 这很酷.我通常不会被冒犯...只是当有人使用大写时:P开玩笑吧.好吧,你的标准适用于某些资源,如字符串和drawables ...但是,正如文档所说,它不适用于定向测量等等.此外,最重要的是,这不会让你得到一个全局上下文有时对可能需要它的东西有用(例如,提出一个`Toast`,获得一个`SharedPreference`实例,打开一个数据库,正如我的拉丁语老师所说:*等等*). (2认同)

Vit*_*lyi 20

我的 Kotlin 解决方案是使用静态应用程序上下文:

class App : Application() {
    companion object {
        lateinit var instance: App private set
    }

    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}
Run Code Online (Sandbox Code Playgroud)

还有我到处使用的 Strings 类:

object Strings {
    fun get(@StringRes stringRes: Int, vararg formatArgs: Any = emptyArray()): String {
        return App.instance.getString(stringRes, *formatArgs)
    }
}
Run Code Online (Sandbox Code Playgroud)

所以你可以有一种干净的方式来获取资源字符串

Strings.get(R.string.some_string)
Strings.get(R.string.some_string_with_arguments, "Some argument")
Run Code Online (Sandbox Code Playgroud)

请不要删除这个答案,让我保留一个。

  • 简单干净的解决方案,感谢您分享代码! (2认同)
  • 谢谢!尽管这是一个已知的解决方案,但“Strings”很有帮助。 (2认同)

Khe*_*raj 7

捷径

我用App.getRes()而不是App.getContext().getResources()(正如@Cristian 回答的那样)

在代码中的任何地方使用都非常简单!

因此,这是一个独特的解决方案,您可以通过它从任何地方访问资源,例如Util class.

(1) 创建或编辑您的Application班级。

import android.app.Application;
import android.content.res.Resources;

public class App extends Application {
    private static App mInstance;
    private static Resources res;


    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
        res = getResources();
    }

    public static App getInstance() {
        return mInstance;
    }

    public static Resources getRes() {
        return res;
    }

}
Run Code Online (Sandbox Code Playgroud)

(2) 将名称字段添加到您的manifest.xml <application标签中。(或如果已经存在则跳过)

<application
        android:name=".App"
        ...
        >
        ...
    </application>
Run Code Online (Sandbox Code Playgroud)

现在你可以走了。

App.getRes().getString(R.string.some_id)在代码中的任何地方使用。


Gre*_*ein 6

还有另一种可能性。我从这样的资源加载 OpenGl 着色器:

static private String vertexShaderCode;
static private String fragmentShaderCode;

static {
    vertexShaderCode = readResourceAsString("/res/raw/vertex_shader.glsl");
    fragmentShaderCode = readResourceAsString("/res/raw/fragment_shader.glsl");
}

private static String readResourceAsString(String path) {
    Exception innerException;
    Class<? extends FloorPlanRenderer> aClass = FloorPlanRenderer.class;
    InputStream inputStream = aClass.getResourceAsStream(path);

    byte[] bytes;
    try {
        bytes = new byte[inputStream.available()];
        inputStream.read(bytes);
        return new String(bytes);
    } catch (IOException e) {
        e.printStackTrace();
        innerException = e;
    }
    throw new RuntimeException("Cannot load shader code from resources.", innerException);
}
Run Code Online (Sandbox Code Playgroud)

如您所见,您可以访问路径/res/... Change 中的任何资源aClass到您的班级。这也是我在测试中加载资源的方式(androidTests)