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

发布于 2024-10-06 20:58:24 字数 132 浏览 2 评论 0 原文

我想在对小部件执行诸如 setText 之类的其他操作之前从 xml 文件中读取字符串,那么如果没有活动对象来调用 ,我该如何做到这一点getResources() 上吗?

I want to read strings from an xml file before I do much of anything else like setText on widgets, so how can I do that without an activity object to call getResources() on?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

怎樣才叫好 2024-10-13 20:58:24
  1. 创建Application的子类,例如public类App extends Application {
  2. AndroidManifest.xml 标记的 android:name 属性设置为指向您的新类,例如 android:name=".App"
  3. 在应用实例的 onCreate() 方法中,保存您的上下文(例如 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;
    }
}

现在您可以使用: <每当您想要获取上下文时,请使用 code>App.getContext() ,然后使用 getResources() (或 App.getContext().getResources()) 。

  1. Create a subclass of Application, for instance public class App extends Application {
  2. Set the android:name attribute of your <application> tag in the AndroidManifest.xml to point to your new class, e.g. android:name=".App"
  3. In the onCreate() method of your app instance, save your context (e.g. this) to a static field named mContext and create a static method that returns this field, e.g. getContext():

This is how it should look:

public class App extends Application{

    private static Context mContext;

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

    public static Context getContext(){
        return mContext;
    }
}

Now you can use: App.getContext() whenever you want to get a context, and then getResources() (or App.getContext().getResources()).

伪装你 2024-10-13 20:58:24

仅适用于系统资源!

使用

Resources.getSystem().getString(android.R.string.cancel)

您可以在应用程序中的任何地方使用它们,甚至在静态常量声明中!

For system resources only!

Use

Resources.getSystem().getString(android.R.string.cancel)

You can use them everywhere in your application, even in static constants declarations!

愁杀 2024-10-13 20:58:24

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

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

    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}

以及我到处使用的 Strings 类:

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

这样您就可以有一种干净的方式来获取资源字符串

Strings.get(R.string.some_string)
Strings.get(R.string.some_string_with_arguments, "Some argument")

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

My Kotlin solution is to use a static Application context:

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

    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}

And the Strings class, that I use everywhere:

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

So you can have a clean way of getting resource strings

Strings.get(R.string.some_string)
Strings.get(R.string.some_string_with_arguments, "Some argument")

Please don't delete this answer, let me keep one.

一枫情书 2024-10-13 20:58:24

快捷方式

我使用 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;
    }

}

(2) 将名称字段添加到 manifest.xml 标记中。 (或者如果已经存在则跳过此)

<application
        android:name=".App"
        ...
        >
        ...
    </application>

现在您可以开始了。

在代码中的任何位置使用 App.getRes().getString(R.string.some_id)

Shortcut

I use App.getRes() instead of App.getContext().getResources() (as @Cristian answered)

It is very simple to use anywhere in your code!

So here is a unique solution by which you can access resources from anywhere like Util class .

(1) Create or Edit your Application class.

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

}

(2) Add name field to your manifest.xml <application tag. (or Skip this if already there)

<application
        android:name=".App"
        ...
        >
        ...
    </application>

Now you are good to go.

Use App.getRes().getString(R.string.some_id) anywhere in code.

平安喜乐 2024-10-13 20:58:24

还有另一种可能性。我从这样的资源加载 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);
}

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

There is also another possibilty. I load OpenGl shaders from resources like this:

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

As you can see, you can access any resource in path /res/...
Change aClass to your class. This also how I load resources in tests (androidTests)

陈年往事 2024-10-13 20:58:24

Singleton:

package com.domain.packagename;

import android.content.Context;

/**
 * Created by Versa on 10.09.15.
 */
public class ApplicationContextSingleton {
    private static PrefsContextSingleton mInstance;
    private Context context;

    public static ApplicationContextSingleton getInstance() {
        if (mInstance == null) mInstance = getSync();
        return mInstance;
    }

    private static synchronized ApplicationContextSingleton getSync() {
        if (mInstance == null) mInstance = new PrefsContextSingleton();
        return mInstance;
    }

    public void initialize(Context context) {
        this.context = context;
    }

    public Context getApplicationContext() {
        return context;
    }

}

在您的 Application 子类中初始化 Singleton:

package com.domain.packagename;

import android.app.Application;

/**
 * Created by Versa on 25.08.15.
 */
public class mApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ApplicationContextSingleton.getInstance().initialize(this);
    }
}

如果我没记错的话,这会为您提供一个到 applicationContext 的钩子,使用 ApplicationContextSingleton.getInstance.getApplicationContext(); 调用它代码>
您不需要在任何时候清除它,因为当应用程序关闭时,它会随之消失。

请记住更新 AndroidManifest.xml 以使用此 Application 子类:

<?xml version="1.0" encoding="utf-8"?>

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.domain.packagename"
    >

<application
    android:allowBackup="true"
    android:name=".mApplication" <!-- This is the important line -->
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    android:icon="@drawable/app_icon"
    >

现在您也应该能够从任何地方使用 ApplicationContextSingleton.getInstance().getApplicationContext().getResources()应用程序子类无法做到的极少数地方。

如果您发现这里有什么问题请告诉我,谢谢。 :)

The Singleton:

package com.domain.packagename;

import android.content.Context;

/**
 * Created by Versa on 10.09.15.
 */
public class ApplicationContextSingleton {
    private static PrefsContextSingleton mInstance;
    private Context context;

    public static ApplicationContextSingleton getInstance() {
        if (mInstance == null) mInstance = getSync();
        return mInstance;
    }

    private static synchronized ApplicationContextSingleton getSync() {
        if (mInstance == null) mInstance = new PrefsContextSingleton();
        return mInstance;
    }

    public void initialize(Context context) {
        this.context = context;
    }

    public Context getApplicationContext() {
        return context;
    }

}

Initialize the Singleton in your Application subclass:

package com.domain.packagename;

import android.app.Application;

/**
 * Created by Versa on 25.08.15.
 */
public class mApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ApplicationContextSingleton.getInstance().initialize(this);
    }
}

If I´m not wrong, this gives you a hook to applicationContext everywhere, call it with ApplicationContextSingleton.getInstance.getApplicationContext();
You shouldn´t need to clear this at any point, as when application closes, this goes with it anyway.

Remember to update AndroidManifest.xml to use this Application subclass:

<?xml version="1.0" encoding="utf-8"?>

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.domain.packagename"
    >

<application
    android:allowBackup="true"
    android:name=".mApplication" <!-- This is the important line -->
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    android:icon="@drawable/app_icon"
    >

Now you should be able to use ApplicationContextSingleton.getInstance().getApplicationContext().getResources() from anywhere, also the very few places where application subclasses can´t.

Please let me know if you see anything wrong here, thank you. :)

冷…雨湿花 2024-10-13 20:58:24

另一个解决方案:

如果非静态外部类中有静态子类,则可以通过外部类中的静态变量从子类内部访问资源,这些静态变量在创建外部类时进行初始化。就像

public class Outerclass {

    static String resource1

    public onCreate() {
        resource1 = getString(R.string.text);
    }

    public static class Innerclass {

        public StringGetter (int num) {
            return resource1; 
        }
    }
}

我将它用于 FragmentActivity 中静态 FragmentPagerAdapter 的 getPageTitle(intposition) 函数一样,由于 I8N,它很有用。

Another solution:

If you have a static subclass in a non-static outer class, you can access the resources from within the subclass via static variables in the outer class, which you initialise on creation of the outer class. Like

public class Outerclass {

    static String resource1

    public onCreate() {
        resource1 = getString(R.string.text);
    }

    public static class Innerclass {

        public StringGetter (int num) {
            return resource1; 
        }
    }
}

I used it for the getPageTitle(int position) Function of the static FragmentPagerAdapter within my FragmentActivity which is useful because of I8N.

飘逸的'云 2024-10-13 20:58:24

我想,还有更多的办法。
但有时,我会使用这种解决方案。 (全球完整):

    import android.content.Context;

    import <your package>.R;

    public class XmlVar {

        private XmlVar() {
        }

        private static String _write_success;

        public static String write_success() {
            return _write_success;
        }


        public static void Init(Context c) {
            _write_success = c.getResources().getString(R.string.write_success);
        }
    }
//After activity created:
cont = this.getApplicationContext();
XmlVar.Init(cont);
//And use everywhere
XmlVar.write_success();

I think, more way is possible.
But sometimes, I using this solution. (full global):

    import android.content.Context;

    import <your package>.R;

    public class XmlVar {

        private XmlVar() {
        }

        private static String _write_success;

        public static String write_success() {
            return _write_success;
        }


        public static void Init(Context c) {
            _write_success = c.getResources().getString(R.string.write_success);
        }
    }
//After activity created:
cont = this.getApplicationContext();
XmlVar.Init(cont);
//And use everywhere
XmlVar.write_success();
迷爱 2024-10-13 20:58:24

我从静态函数加载 openGL ES 的着色器。

请记住文件名和目录名必须使用小写,否则操作将失败

public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...

    public static int loadShader() {
        //    Read file as input stream
        InputStream inputStream = MyGLRenderer.class.getResourceAsStream("/res/raw/vertex_shader.txt");

        //    Convert input stream to string
        Scanner s = new Scanner(inputStream).useDelimiter("\\A");
        String shaderCode = s.hasNext() ? s.next() : "";
    }

    ...

}

I load shader for openGL ES from static function.

Remember you must use lower case for your file and directory name, or else the operation will be failed

public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...

    public static int loadShader() {
        //    Read file as input stream
        InputStream inputStream = MyGLRenderer.class.getResourceAsStream("/res/raw/vertex_shader.txt");

        //    Convert input stream to string
        Scanner s = new Scanner(inputStream).useDelimiter("\\A");
        String shaderCode = s.hasNext() ? s.next() : "";
    }

    ...

}
会傲 2024-10-13 20:58:24

我正在使用 API 级别 27,经过大约两天的努力,找到了最佳解决方案。如果您想从不是从 Activity 或 Application 派生的类中读取 xml 文件,请执行以下操作。

  1. 将 testdata.xml 文件放入资产目录中。

  2. 编写以下代码来解析测试数据文档。

     InputStream inputStream = this.getClass().getResourceAsStream("/assets/testdata.xml");
    
        // 创建一个新的 DocumentBuilderFactory
        DocumentBuilderFactory 工厂 = DocumentBuilderFactory.newInstance();
        // 使用工厂创建文档生成器
        DocumentBuilder 构建器=factory.newDocumentBuilder();
        // 从输入流创建一个新文档
        文档 doc = builder.parse(inputStream);
    

I am using API level 27 and found a best solution after struggling for around two days. If you want to read a xml file from a class which doesn't derive from Activity or Application then do the following.

  1. Put the testdata.xml file inside the assets directory.

  2. Write the following code to get the testdata document parsed.

        InputStream inputStream = this.getClass().getResourceAsStream("/assets/testdata.xml");
    
        // create a new DocumentBuilderFactory
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // use the factory to create a documentbuilder
        DocumentBuilder builder = factory.newDocumentBuilder();
        // create a new document from input stream
        Document doc = builder.parse(inputStream);
    
喜爱皱眉﹌ 2024-10-13 20:58:24

在没有上下文的情况下将图像资源作为 InputStream 获取:

Class<? extends MyClass> aClass = MyClass.class;
URL r = aClass.getResource("/res/raw/test.png");
URLConnection urlConnection = r.openConnection();
return new BufferedInputStream(urlConnection.getInputStream());

如果您需要文件的目录树,它也可以工作(资产支持子目录):

URL r = aClass.getResource("/assets/images/base/2.png");

Getting image resouse as InputStream without context:

Class<? extends MyClass> aClass = MyClass.class;
URL r = aClass.getResource("/res/raw/test.png");
URLConnection urlConnection = r.openConnection();
return new BufferedInputStream(urlConnection.getInputStream());

If you need derectory tree for your files, it will also works (assets supports sub-dirs):

URL r = aClass.getResource("/assets/images/base/2.png");
枫以 2024-10-13 20:58:24

为什么你不尝试

Resources.getSystem().getString(R.string.foo);

why you dont try

Resources.getSystem().getString(R.string.foo);
多情癖 2024-10-13 20:58:24

这是您可以尝试的另一种略有不同的方法。

您可以像其他解决方案提到的那样对 Application 类进行子类化,并存储对 Resources 实例的静态引用。

创建一个应用程序类并在 onCreate 方法中初始化 Resources 变量。当您的应用程序启动时将调用此函数。我们可以在这里使用 WeakReference 来防止由于将此实例存储为静态变量而可能发生的内存泄漏(尽管这种情况不太可能发生),

public class App extends Application {
    private static WeakReference<Resources> res;

因为您提到您只想从中检索字符串xml资源声明,不需要将此资源变量暴露给其他类,用于资源实例的封装,防止泄露。因此,您可以将引用存储为私有变量。

请记住在 onCreate 中初始化此变量:

@Override 
public void onCreate() { 
    super.onCreate(); 
    res = new WeakReference<>(getResources());
}

我们还需要将应用程序的 android:name 声明为 .App(或您设置的任何其他名称)到)在 AndroidManifest.xml 中的 application 标记下。

<application android:name=".App"
........... other attributes here ...........

检索字符串资源的另一种方法不是使用其他类中的 Resources 实例(或 Context 实例),而是获取 App类以静态方法为您获取此信息。这使实例保持封装/私有。

您可以在App类中使用静态方法来检索这些值(例如getStringGlobal,只是不要调用它getString,因为它会与默认方法)

public static String getStringGlobal(@StringRes int resId) { 
   if (res != null && res.get() != null) { 
        return res.get().getString(resId); 
   } else {
        // This should not happen, you should throw an exception here, or you can return a fallback string to ensure the app still runs
    }
}

如所见,您还可以添加错误处理,以防 Resources 的实例不可用(这不应该发生,但以防万一)。

来检索字符串资源:

App.getStringGlobal(R.string./*your string resource name*/)

然后,您可以通过调用您的 App.java

public class App extends Application { 
    private static WeakReference<Resources> res;

    @Override 
    public void onCreate() { 
        super.onCreate(); 
        res = new WeakReference<>(getResources());    
    }

    public static String getStringGlobal(@StringRes int resId) { 
       if (res != null && res.get() != null) { 
            return res.get().getString(resId); 
       } else {
        // This should not happen(reference to Resources invalid), you should throw an exception here, or you can return a fallback string to ensure the app still runs
       }
    }
}

Here is an alternative, slightly different, approach that you may try.

You could subclass the Application class like what other solutions mentioned, and store a static reference to an instance of Resources.

Create an application class and initialise the Resources variable in the onCreate method. This will be called when your app starts. We can use WeakReference here to prevent memory leaks that might happen as a result of storing this instance as a static variable(although it is very unlikely to happen)

public class App extends Application {
    private static WeakReference<Resources> res;

Since you mentioned that you only want to retrieve strings from the xml resource declaration, there is no need to expose this resource variable to other classes, for encapsulation of the resources instance and to prevent it from leaking out. Hence, you may store the reference as a private variable.

Remember to initialise this variable in onCreate:

@Override 
public void onCreate() { 
    super.onCreate(); 
    res = new WeakReference<>(getResources());
}

We also need to declare the application's android:name as .App(or any other name you set it to) in AndroidManifest.xml under the application tag.

<application android:name=".App"
........... other attributes here ...........

Another way of retrieving the string resource is not by using the Resources instance in other classes(or the Context instance), but to get the App class to get this for you in a static method. This keeps the instance encapsulated/private.

You can use a static method in your App class to retrieve these values(e.g. getStringGlobal, just do not call it getString as it will conflict with the default method)

public static String getStringGlobal(@StringRes int resId) { 
   if (res != null && res.get() != null) { 
        return res.get().getString(resId); 
   } else {
        // This should not happen, you should throw an exception here, or you can return a fallback string to ensure the app still runs
    }
}

As seen, you can also add error handling in case the instance of Resources is not available(this should not happen, but just in case).

You can then retrieve the string resource by calling

App.getStringGlobal(R.string./*your string resource name*/)

So your App.java:

public class App extends Application { 
    private static WeakReference<Resources> res;

    @Override 
    public void onCreate() { 
        super.onCreate(); 
        res = new WeakReference<>(getResources());    
    }

    public static String getStringGlobal(@StringRes int resId) { 
       if (res != null && res.get() != null) { 
            return res.get().getString(resId); 
       } else {
        // This should not happen(reference to Resources invalid), you should throw an exception here, or you can return a fallback string to ensure the app still runs
       }
    }
}
昇り龍 2024-10-13 20:58:24

从静态上下文获取资源的另一个选择是将类的上下文作为参数解析到函数中

例如:

   // usage
   changeColor(myActivityName.this, foo);

   public static void changeColor(Context context, TextView bar) {
       bar.setTextColor(context.getResources().getColor(R.color.Black));
   }

Another option to get a resource from a static context would be to parse the context of your class into the function as an argument.

For example:

   // usage
   changeColor(myActivityName.this, foo);

   public static void changeColor(Context context, TextView bar) {
       bar.setTextColor(context.getResources().getColor(R.color.Black));
   }
不美如何 2024-10-13 20:58:24

在您实现静态函数的类中,您可以从该类调用private\public方法。 private\public 方法可以访问getResources

例如:

public class Text {

   public static void setColor(EditText et) {
      et.resetColor(); // it works

      // ERROR
      et.setTextColor(getResources().getColor(R.color.Black)); // ERROR
   }

   // set the color to be black when reset
   private void resetColor() {
       setTextColor(getResources().getColor(R.color.Black));
   }
}

并且从其他类\活动中,您可以调用:

Text.setColor('some EditText you initialized');

In your class, where you implement the static function, you can call a private\public method from this class. The private\public method can access the getResources.

for example:

public class Text {

   public static void setColor(EditText et) {
      et.resetColor(); // it works

      // ERROR
      et.setTextColor(getResources().getColor(R.color.Black)); // ERROR
   }

   // set the color to be black when reset
   private void resetColor() {
       setTextColor(getResources().getColor(R.color.Black));
   }
}

and from other class\activity, you can call:

Text.setColor('some EditText you initialized');
薄荷→糖丶微凉 2024-10-13 20:58:24

如果你有上下文,我的意思是里面;

public void onReceive(Context context, Intent intent){

}

您可以使用此代码来获取资源:

context.getResources().getString(R.string.app_name);

if you have a context, i mean inside;

public void onReceive(Context context, Intent intent){

}

you can use this code to get resources:

context.getResources().getString(R.string.app_name);
墨小沫ゞ 2024-10-13 20:58:24
public Static Resources mResources;

 @Override
     public void onCreate()
     {
           mResources = getResources();
     }
public Static Resources mResources;

 @Override
     public void onCreate()
     {
           mResources = getResources();
     }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文