66

In my application I have many classes and activities. Droid is a class which does not have context. Mygame is a class which extends SurfaceView and implements SurfaceHolder.Callback. I am creating an object of Droid in mygame class and setting the background image and position for it. The code I have written for this is given below.

block1 = new Droid(BitmapFactory.decodeResource(getResources(), R.drawable.birdpic), 100, 10);

The constructor of Droid class is given below.

public Droid(Bitmap bitmap, int x, int y) {

    this.bitmap = bitmap;
    this.x = x;
    this.y = y;
}   

In a particular scenario i have to set the background image and position of the Droid object from the Droid class itself.Here i am facing the issue.Given below is the code snippet to do this.

if(checkflag)
{
    myObj.centerblock=new Droid(BitmapFactory.decodeResource(getResources(), R.drawable.blast), myObj.xpos, myObj.ypos);
}   

The problem is that the Droid class has no context. So I cannot use getResources() here. I have tried the code below but it crashes.

if(checkflag)
{
    myObj.centerblock=new Droid(BitmapFactory.decodeResource(myObj.getResources(), R.drawable.blast), myObj.xpos, myObj.ypos);
}

Can anybody help me. I just want to set the background image and position it for the Droid object from the Droid class itself.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
andro-girl
  • 7,989
  • 22
  • 71
  • 94
  • 1
    possible duplicate of [Using getResources() in non-activity class](http://stackoverflow.com/questions/7666589/using-getresources-in-non-activity-class) – Richard Le Mesurier May 21 '14 at 10:43

5 Answers5

57

A Context is a handle to the system; it provides services like resolving resources, obtaining access to databases and preferences, and so on. It is an "interface" that allows access to application specific resources and class and information about application environment. Your activities and services also extend Context to they inherit all those methods to access the environment information in which the application is running.

This means you must have to pass context to the specific class if you want to get/modify some specific information about the resources. You can pass context in the constructor like

public classname(Context context, String s1) 
{
...
}
Ali
  • 1,462
  • 2
  • 14
  • 16
  • is it possible to set context for Droid class...it is not extending activity or any other classes – andro-girl Nov 23 '11 at 08:46
  • 2
    it need not to extend an activity. You may pass context to this class when initializing this class from some activity. – Ali Nov 23 '11 at 09:01
30

Example: Getting app_name string:

Resources.getSystem().getString( R.string.app_name )
j0k
  • 22,600
  • 28
  • 79
  • 90
clive
  • 317
  • 3
  • 2
  • 19
    This only uses the System resources, not the App resources - which in 99% cases won't work – Adam Mar 17 '13 at 21:04
  • yeah...this did not work for me either. I needed to get to the app resources for an enum translation to strings and those were not found. Ended up having to create a function that mapped the enum to a resource and used the Activity as talked about elsewhere in this post. – Go Rose-Hulman Mar 04 '14 at 00:33
29

The normal solution to this is to pass an instance of the context to the class as you create it, or after it is first created but before you need to use the context.

Another solution is to create an Application object with a static method to access the application context although that couples the Droid object fairly tightly into the code.

Edit, examples added

Either modify the Droid class to be something like this

 public Droid(Context context,int x, int y) {
    this.bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.birdpic);
    this.x = x;
    this.y = y;
    }   

Or create an Application something like this:

public class App extends android.app.Application
{
    private static App mApp = null;
    /* (non-Javadoc)
     * @see android.app.Application#onCreate()
     */
    @Override
    public void onCreate()
    {
        super.onCreate();
        mApp = this;
    }
    public static Context context()
    {
        return mApp.getApplicationContext();
    }
}

And call App.context() wherever you need a context - note however that not all functions are available on an application context, some are only available on an activity context but it will certainly do with your need for getResources().

Please note that you'll need to add android:name to your application definition in your manifest, something like this:

<application
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:name=".App" >
zeetoobiker
  • 2,789
  • 1
  • 18
  • 10
  • Usind android bitmap also provides tight coupling to android code. I usually try to separate interface related code and appliction specific stuff (I'm not alays successfull) – Konstantin Pribluda Nov 23 '11 at 07:42
  • @zeetoobiker ...can you please explain these things?i ddnt get you..i am not that familiar with android. – andro-girl Nov 23 '11 at 08:12
  • I didn't really mean tight coupling to the Android code (assuming you gave it access to the Application object with a static method), rather that the Droid class will be tightly coupled to the project it's currently in - you won't be able to use it in a different project without re-writing the internals. To be honest, a class in an Android app dealing with display functions is going to be tightly coupled to Android so I wouldn't worry about that. – zeetoobiker Nov 24 '11 at 14:25
  • seethalakshim - I've added some examples to the answer to hopefully explain it a little more. – zeetoobiker Nov 24 '11 at 14:33
  • Findbugs says that writing a static variable from an instance method is generally bad practice, I am curious why would this approach be ok, considering the fact that this is something Android specific. – r1k0 Jun 11 '14 at 08:02
  • So, should the App object be used as a singleton (object)? – Bruiser Oct 27 '14 at 18:44
  • I think the static access can make a problem with the Garbace Collector. Is there any way to prevent this? – andreas Sep 08 '15 at 21:30
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:
 block1 = new Droid(BitmapFactory.decodeResource(ctx.getResources(), R.drawable.birdpic), 100, 10);
 //OR
 builder.setLargeIcon(BitmapFactory.decodeResource(ctx.getResources(), R.drawable.birdpic));
 //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);
Elroy
  • 1,530
  • 2
  • 15
  • 16
0

It can easily be done if u had declared a class that extends from Application

This class will be like a singleton, so when u need a context u can get it just like this:

I think this is the better answer and the cleaner

Here is my code from Utilities package:

 public static String getAppNAme(){
     return MyOwnApplication.getInstance().getString(R.string.app_name);
 }
Catluc
  • 1,775
  • 17
  • 25