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


Answers:


373
  1. 创建一个的子类Application,例如public class App extends Application {
  2. 在中设置标签的android:name属性以指向您的新类,例如<application>AndroidManifest.xmlandroid: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;
    }
}

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


9
应用程序实例不是动态值,@ Gangnus怎么这样?无论如何-我发现在Android中依靠静态的艰难方法不过是头疼。“现在您看到了,现在您不知道了”
波士顿

18
我无法避免认为这是“黑客”。尽管我一直在使用它(感谢您提供此解决方案,因为我正要本地化本地化),所以我感觉很不好,因为某种原因这是错误的。
Illiax

8
与仅将Context作为应用程序中每个静态方法中的第一个参数传递时相比,更好还是更坏?前者感觉很笨拙,而后者则不必要地重复。
戴夫

12
文档说:“通常不需要子类化Application。在大多数情况下,静态单例可以以更模块化的方式提供相同的功能。如果您的单例需要全局上下文(例如,注册广播接收器),则该函数可以检索可以为它提供一个上下文,该上下文在首次构造单例时在内部使用Context.getApplicationContext()。” 〜developer.android.com/reference/android/app/Application.html
大卫·dçè弗雷塔斯

25
为了避免内存泄漏,最好将Context存储在WeakReference中:private static WeakReference <Context> mContext; 公共静态上下文getContext(){return mContext.get(); 当应用程序崩溃并且您不能将静态上下文设置为null时,这应该会有所帮助(WeakReference可以被垃圾收集)。
FrankKrumnow

102

仅用于系统资源!

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

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


2
这很酷。我通常不会生气...只是当有人使用大写字母时:P开玩笑。好的,您的标准适用于某些资源,例如字符串和可绘制对象...但是,正如文档所述,它不适用于定向度量等。此外,最重要的是,这将使您无法获得全局上下文有时对可能需要它的事情很有用(Toast例如,举一个SharedPreference实例,获取一个实例,打开一个数据库,正如我的拉丁语老师说的:et cetera)。
2012年

1
你甚至不能通过它赢得全世界的和平。但这有助于解决此处问题所提出的问题。我并不是说它解决了所有任务,只是说它几乎解决了应用程序中每个位置的任务。我一直在寻找这种解决方案10个月-一直使用Android。现在我找到了。
Gangnus 2012年

18
您在这里一定要小心。不要尝试使用这种方法来查找您的应用程序资源。阅读详细信息:返回一个全局共享资源对象,该对象仅提供对系统资源(无应用程序资源)的访问,并且没有为当前屏幕进行配置(不能使用尺寸单位,不会根据方向发生变化,等等)。
波士顿

4
@ DroidIn.net引用:“但是仅用于系统资源!”。我知道/ *叹息/ *
Gangnus

1
我使用它时遇到了一个异常:android.content.res.Resources $ NotFoundException:字符串资源ID
vinidog

6

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

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")

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


简单干净的解决方案,感谢您分享代码!
Jeehut

谢谢!尽管这是一个已知的解决方案,Strings但很有帮助。
CoolMind

4

还有另一种可能性。我从如下资源加载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)


1
当我没有Activity时(对我来说,开发一个没有类可以扩展Application的插件),对我唯一有效的解决方案。谢谢+1
itaton '18

3

单身人士:

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()了,也可以在很少的地方使用应用程序子类。

如果您在这里看到任何错误,请告诉我,谢谢。:)


2

另一个解决方案:

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

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(int position)函数,由于I8N,该函数非常有用。


2

捷径

我用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 getResourses() {
        return res;
    }

}

(2)将名称字段添加到manifest.xml <application标签。(或者如果已经存在,请跳过此步骤)

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

现在你很好。

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


0

我认为,更多的方法是可能的。但是有时候,我使用这种解决方案。(全球):

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

0

我从静态功能为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() : "";
    }

    ...

}

0
public Static Resources mResources;

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

好吧,问题是,getResources()需要一个上下文。因此,这可能并不是“没有活动对象”的解决方案(您在其中发布了onCreate()方法)
Tobias Reich

0

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

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

  2. 编写以下代码以获取解析的testdata文档。

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

-1

在实现静态功能的类中,可以从此类调用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');

-1

如果你有背景,我的意思是里面;

public void onReceive(Context context, Intent intent){

}

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

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

2
问题的标题是在静态上下文中说的。您的答案不涵盖其中。
Rune Schjellerup Philosof
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.