15

I have found one answer that appears to say I should create a separate class and make a static MyApplication object and make a get method. Then any class can call MyApplication.get() to retrieve the context.

Is there any other cleaner way? This is my situation:

I have a class A and a class B. Class A contains an object from class B (let's call the object b). In class A I call, "b.play()". However, I get a null pointer exception because class B needs to pass a context to the MediaPlayer.create() method.

Until now I threw together a hack and from class A I called.... "b.play(this)" and simply passed the context to B. However that is pretty ugly and looks like a bad use of OOP.

Any thoughts?

Community
  • 1
  • 1
  • Even though this question is older, better discussion and clearer answers are happening on this duplicate question: http://stackoverflow.com/questions/7666589/using-getresources-in-non-activity-class – tir38 May 02 '16 at 19:31

4 Answers4

13

This problem seem to arise a lot in Android development. One solution to obtaining a reference to a specific Context is subclassing the Application and grab a reference to the Context which you want.

public class MyApplication extends Application { 

private Context context;

@Override
public onCreate() {
  super.onCreate();
  this.context = getApplicationContext() // Grab the Context you want.
}

public static Context getApplicationContext() { return this.context; }
}

This solution however requires that you specify the name of your subclass in your manifest.

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

You can then use this anywhere in your application like this in non-activity classes.

MyApplication.getContext();  // Do something with the context! :)
Entalpi
  • 2,005
  • 22
  • 33
  • You can't return an instance variable from a static function. You could refactor the context variable to be static - but that would be a potential memory leak. – winklerrr Jan 23 '17 at 11:01
  • It should be possible since the unintialized value of a reference is just null but otherwise the variable should, as you say, be declared static. :) – Entalpi Jan 23 '17 at 11:35
  • 3
    And a static context should be avoided due to its memory leak potential. – winklerrr Jan 23 '17 at 13:22
  • @winklerrr What is your solution so ? – user1510006 Apr 27 '17 at 13:18
  • 1
    @user1510006 pass a `Context` (could be your activity or the application context for example) to your non-activity class through its constructor. If you need to make sure, that you are working with the application context just call `context.getApplicationContext()` inside your constructor. – winklerrr Apr 28 '17 at 06:33
11

If class B requires a Context to operate, then I don't see any problem having class A provide that to it (through a parameter on the play method, a parameter in a constructor, etc).

I don't think you are doing any poor OOP by providing class B the dependencies that it needs to do it's job.

Brian Yarger
  • 1,965
  • 18
  • 17
  • Hmm, if it's not frowned upon I think I will keep it, but pass the context within the constructor of class B to avoid passing the context a bunch of times. Thanks! Thus far this context business has been the most complicated part of Android development for me~ –  Jul 28 '11 at 23:59
  • 3
    This is actually extremely good OO and makes testing easier. Dependancy injection is a common design pattern. – jlindenbaum Aug 29 '12 at 15:59
  • Passing Context to the constructor is preferred as opposed to passing to each method within a class, since passing to a class method sometimes could result in a NullPointerException. – ChuongPham Aug 07 '14 at 15:25
1

I've answered also here.

You can do that using ContextWrapper, as described here.

For example:

public class MyContextWrapper extends ContextWrapper {

    public MyContextWrapper(Context base) {
      super(base);
   }

   public void someMethod() {
      // MediaPlayer.create(this, ...)
   }

}
Community
  • 1
  • 1
ET-CS
  • 6,334
  • 5
  • 43
  • 73
  • 2
    And how do I get an instance of `MyContextWrapper`? I need to pass a `Context` to it which is what I am after in the first place. – Suhas Apr 11 '17 at 10:14
1

Passing this around is a viable way of doing things, especially if this is the activity that creates the object in need of a Context. Sometimes, I'll put the Context into the constructor (like public MyObject(Context context){this.context = context;}), so that you don't need to send it every time. However, if your object is shared across multiple Activities, you should probably update the context it is looking at with the new Activity, though I haven't tested what happens if you use the old activity.

AlbeyAmakiir
  • 2,217
  • 6
  • 25
  • 48
  • 4
    `I'll put the Context into the constructor [and then save it]` That is a great way to cause a memory leak. `though I haven't tested what happens if you use the old activity.` Almost certainly an exception will be thrown, and you'll have leaked a context. – Falmarri Jul 28 '11 at 23:58
  • 1
    So passing through the method is better? How about the overhead involved in passing a context multiple times? –  Jul 29 '11 at 00:01
  • @Falmarri: Ah, yes. You should set the context to null when you intend to close it, just to be sure, though unreachable closed loops of references are candidates for garbage collection anyway. – AlbeyAmakiir Jul 29 '11 at 00:50
  • @Google: There is practically 0 overhead in passing an object to an object. If your object's lifecycle is tied to the lifecycle of the context, then passing it is fine. But just beware you now have the potential to leak a context. – Falmarri Jul 29 '11 at 00:53
  • 2
    @AlbeAmakiir: `though unreachable closed loops of references are candidates for garbage collection anyway` The garbage collector is not that smart. Contexts are extremely complex objects. It's true they should eventually be garbage collected. However they most likely won't because contexts have a very specific lifecycle and are held in various places that the GC can't check. – Falmarri Jul 29 '11 at 00:55
  • How can I be sure the context isn't leaked? –  Jul 29 '11 at 00:59
  • @Falmarri: Held in places the GC can't check? That's something I have not heard before, and sounds completely bizarre. I also can't find anything to back that up. Similarly, the garbage collector should be that smart, unless they are ignoring part of the specification of java (which they might, because it's not quite Java anyway). – AlbeyAmakiir Jul 29 '11 at 01:22
  • @AlbeyAmakiir: Native code can hold references to contexts. I'm pretty sure that if you pass a reference to a Context to native code, and then lose the reference in native code, your context has been leaked since the JVM has no idea what the native code is doing, and the GC can't assume that it's eligible for GC. – Falmarri Aug 04 '11 at 00:24
  • @Google: Don't hold strong references to contexts in objects whose lifecycle is greater than the lifecycle of the context. – Falmarri Aug 04 '11 at 00:25