Using getResources() in non-activity class
Asked Answered
P

12

134

I am trying to use getResources method in a non-activity class. How do I get the reference to the "resources" object so that I can access the xml file stored under resources folder?

Example:

XmlPullParser xpp = getResources().getXml(R.xml.samplexml);
Peace answered 5/10, 2011 at 19:26 Comment(2)
It's normally not a good idea to pass around Context objects in Android. It can lead to memory leaks. See my answer for a less risky solution.Cohbert
possible duplicate of How to retrieve a context from a non-activity class?Buchheim
L
166

You will have to pass a context object to it. Either this if you have a reference to the class in an activty, or getApplicationContext()

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        RegularClass regularClass = new RegularClass(this);
    }
}

Then you can use it in the constructor (or set it to an instance variable):

public class RegularClass(){
    private Context context;

    public RegularClass(Context current){
        this.context = current;
    }

    public findResource(){
        context.getResources().getXml(R.xml.samplexml);
    }
}

Where the constructor accepts Context as a parameter

Lowestoft answered 5/10, 2011 at 19:29 Comment(5)
It's normally not a good idea to pass around Context objects in Android. It can lead to memory leaks.Cohbert
As a basic rule of thumb sure, but I feel this is somewhat misleading. Context objects are nasty because it is not immediately obvious if it is application-wide or activity-wide. Memory leaks (and crashes) occur when you supply the wrong one. For example, supplying an Activity to a static object which needs a Context and said object isn't destroyed when the Activity is leads to the Activity persisting after onDestroy, since it cannot be GCed due to this other static object. So yes, it can be dangerous, but knowing why it is dangerous I feel is important to mention here.Chalybeate
^Dororo, This is one of the most important comments I've ever read. Proper use of context is rarely if ever, discussed. I get the feeling I've had many an inexplicable bug because of it!Asclepiadaceous
@Chalybeate So do you have any practice suggestion? Should we try to avoid to pass context variables? Then what can we do when we need some api from the activity class?Perusal
Note that you can @Inject resources following this method (define a provider that takes @ApplicationContext context : Context and return context.resources) which is especially useful when using database repositories, where you should be injecting already.Dolabriform
C
40

Its not a good idea to pass Context objects around. This often will lead to memory leaks. My suggestion is that you don't do it. I have made numerous Android apps without having to pass context to non-activity classes in the app. A better idea would be to get the resources you need access to while your in the Activity or Fragment, and hold onto it in another class. You can then use that class in any other classes in your app to access the resources, without having to pass around Context objects.

Cohbert answered 28/8, 2013 at 18:33 Comment(3)
This is good advice thanks. Would it be a problem in a SQLiteOpenHelper? In the constructor, you have to pass a context. It's no longer available in the other methods but I could store it in a private field.Katrinakatrine
@Katrinakatrine Yes there are some classes that require you to pass in a context object. So its best to try to only use those classes like SqLiteOpenHelper in an activity or fragment so you don't have to pass around context object. If its unavoidable just make sure you set your reference to the context object to null when your done to help reduce the risk of memory leaks.Cohbert
Passing context object isn't always bad, as long as you can monitor the activity's life cycle. If not then better use Application context instead of Activity context using getApplicationContext() to avoid memory leaks. See #7144677 for retrieving application context.Lunulate
Z
16

There is one more way without creating a object also. Check the reference. Thanks for @cristian. Below I add the steps which mentioned in the above reference. For me I don't like to create a object for that and access. So I tried to access the getResources() without creating a object. I found this post. So I thought to add it as a answer.

Follow the steps to access getResources() in a non activity class without passing a context through the object.

  • Create a subclass of Application, for instance public class App extends Application {. Refer the code next to the steps.
  • Set the android:name attribute of your <application> tag in the AndroidManifest.xml to point to your new class, e.g. android:name=".App"
  • In the onCreate() method of your app instance, save your context (e.g. this) to a static field named app and create a static method that returns this field, e.g. getContext().
  • Now you can use: App.getContext() whenever you want to get a context, and then we can use App.getContext().getResources() to get values from the resources.

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;
    }
}
Zebulun answered 22/9, 2015 at 20:5 Comment(0)
I
5

here is my answer:

public class WigetControl {
private Resources res;

public WigetControl(Resources res) 
{
    this.res = res;
}

public void setButtonDisable(Button mButton)
{
    mButton.setBackgroundColor(res.getColor(R.color.loginbutton_unclickable));
    mButton.setEnabled(false);
}

}

and the call can be like this:

        WigetControl control = new WigetControl(getResources());
        control.setButtonDisable(btNext);
Irrefragable answered 4/5, 2015 at 8:37 Comment(0)
A
3

this can be done by using

context.getResources().getXml(R.xml.samplexml);
Adult answered 30/7, 2012 at 9:38 Comment(2)
Well, this did the Magic for me. Thanks @AdultVomer
passing Context objects is not a healthy practiceChewink
F
2

We can use context Like this try now Where the parent is the ViewGroup.

Context context = parent.getContext();
Forbearance answered 29/12, 2016 at 15:52 Comment(0)
J
1

well no need of passing the context and doing all that...simply do this

Context context = parent.getContext();

Edit: where parent is the ViewGroup

Jesus answered 26/8, 2013 at 18:41 Comment(1)
I expect you were downvoted for assuming that there is a convenient 'ViewGroup parent' member variable. Rather stupid assumption.Indochina
B
1

This always works for me:

import android.app.Activity;
import android.content.Context;

public class yourClass {

 Context ctx;

 public yourClass (Handler handler, Context context) {
 super(handler);
    ctx = context;
 }

 //Use context (ctx) in your code like this:
 XmlPullParser xpp = ctx.getResources().getXml(R.xml.samplexml);
 //OR
 final Intent intent = new Intent(ctx, MainActivity.class);
 //OR
 NotificationManager notificationManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
 //ETC...

}

Not related to this question but example using a Fragment to access system resources/activity like this:

public boolean onQueryTextChange(String newText) {
 Activity activity = getActivity();
 Context context = activity.getApplicationContext();
 returnSomething(newText);
 return false;
}

View customerInfo = getActivity().getLayoutInflater().inflate(R.layout.main_layout_items, itemsLayout, false);
 itemsLayout.addView(customerInfo);
Boatel answered 21/2, 2015 at 12:41 Comment(0)
S
1

In the tour guide app of Udacity's Basic ANdroid course I have used the concept of Fragments. I got stuck for a while experiencing difficulty to access some string resources described in strings, xml file. Finally got a solution.

This is the main activity class

package com.example.android.tourguidekolkata;

import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState)
{
  //lines of code
   //lines of code
    //lines of code
    YourClass adapter = new YourClass(getSupportFragmentManager(), getApplicationContext()); 
    //lines of code
    // getApplicationContext() method passses the Context of main activity to the class TourFragmentPageAdapter 
}
}

This is the non Activity class that extends FragmentPageAdapter

public class YourClass extends FragmentPagerAdapter {
private String yourStringArray[] = new String[4];
Context context;

public YourClass (FragmentManager fm, Context context)
{
    super(fm);
    this.context = context; // store the context of main activity
    // now you can use this context to access any resource 
    yourStringArray[0] = context.getResources().getString(R.string.tab1);
    yourStringArray[1] = context.getResources().getString(R.string.tab2);
    yourStringArray[2] = context.getResources().getString(R.string.tab3);
    yourStringArray[3] = context.getResources().getString(R.string.tab4);
}
@Override
public Fragment getItem(int position)
 {
 }
@Override
public int getCount() {
return 4;
}

@Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return yourStringArras[position];
}
}
Semiliquid answered 6/9, 2016 at 9:14 Comment(0)
E
0

In simple class declare context and get data from file from res folder

public class FileData
{
      private Context context;

        public FileData(Context current){
            this.context = current;
        }
        void  getData()
        {
        InputStream in = context.getResources().openRawResource(R.raw.file11);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        //write stuff to get Data

        }
}

In the activity class declare like this

public class MainActivity extends AppCompatActivity 
{
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        FileData fileData=new FileData(this);
     }

}
Execrable answered 20/3, 2019 at 6:29 Comment(0)
D
0

in your MainActivity :

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(ResourcesHelper.resources == null){
             ResourcesHelper.resources = getResources();
        }
    }
}

ResourcesHelper :

public class ResourcesHelper {
    public static Resources resources;
}

then use it everywhere

String s = ResourcesHelper.resources.getString(R.string.app_name);
Displace answered 9/4, 2020 at 22:32 Comment(0)
F
-1

I am late but complete solution;: Example Class, Use Context like this :-

public class SingletonSampleClass {

    // Your cute context
    private Context context;
    private static SingletonSampleClass instance;

  // Pass as Constructor
    private SingletonSampleClass(Context context) {
        this.context = context;
    }

    public synchronized static SingletonSampleClass getInstance(Context context) {
        if (instance == null) instance = new SingletonSampleClass(context);
        return instance;
    }

//At end, don't forgot to relase memory
    public void onDestroy() {
       if(context != null) {
          context = null; 
       }
    }
}

Warning (Memory Leaks)

How to solve this?

Option 1: Instead of passing activity context i.e. this to the singleton class, you can pass applicationContext().

Option 2: If you really have to use activity context, then when the activity is destroyed, ensure that the context you passed to the singleton class is set to null.

Hope it helps..∆∆∆∆

Fellmonger answered 23/10, 2019 at 13:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.