How can I get a resource content from a static context?

JavaAndroidStaticConstantsAndroid Resources

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

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!

Solution 3 - Java

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.

Solution 4 - Java

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.

Solution 5 - Java

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)

Solution 6 - Java

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. :)

Solution 7 - Java

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.

Solution 8 - Java

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

Solution 9 - Java

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() : "";
    }

    ...

}

Solution 10 - Java

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

Solution 11 - Java

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

Solution 12 - Java

why you dont try

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

Solution 13 - Java

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

Solution 14 - Java

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

Solution 15 - Java

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

Solution 16 - Java

public Static Resources mResources;

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionlost babyView Question on Stackoverflow
Solution 1 - JavaCristianView Answer on Stackoverflow
Solution 2 - JavaGangnusView Answer on Stackoverflow
Solution 3 - JavaVitalii MalyiView Answer on Stackoverflow
Solution 4 - JavaKhemraj SharmaView Answer on Stackoverflow
Solution 5 - JavaGregory SteinView Answer on Stackoverflow
Solution 6 - JavaVersaView Answer on Stackoverflow
Solution 7 - JavaStephan BrunkerView Answer on Stackoverflow
Solution 8 - Javauser2684935View Answer on Stackoverflow
Solution 9 - Javauser2174870View Answer on Stackoverflow
Solution 10 - JavaJnanaView Answer on Stackoverflow
Solution 11 - JavaYuliia AshomokView Answer on Stackoverflow
Solution 12 - JavanicoView Answer on Stackoverflow
Solution 13 - JavaLCZView Answer on Stackoverflow
Solution 14 - JavaMaor CohenView Answer on Stackoverflow
Solution 15 - JavaErenView Answer on Stackoverflow
Solution 16 - JavaMakvinView Answer on Stackoverflow