92

I don't really get the idea behind how this whole thing works really, so if I have some class A that need the context of a class B which extends Activity, how do i get that context?

I'm searching for a more efficient way than giving the context as a parameter to class A constructor. For example if class A is going to have millions of instances then we would end up having millions of redundant pointer to Context while we should be able somehow to have just one somewhere and a getter function...

Gan
  • 1,349
  • 2
  • 10
  • 27
Ofek Ron
  • 8,354
  • 13
  • 55
  • 103

9 Answers9

63

Ok, I will give a small example on how to do what you ask

public class ClassB extends Activity
{

 ClassA A1 = new ClassA(this); // for activity context

 ClassA A2 = new ClassA(getApplicationContext());  // for application context. 

}
Gan
  • 1,349
  • 2
  • 10
  • 27
46

You can use Application class(public class in android.application package),that is:

Base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in your AndroidManifest.xml's tag, which will cause that class to be instantiated for you when the process for your application/package is created.

To use this class do:

public class App extends Application {

    private static Context mContext;

    public static Context getContext() {
        return mContext;
    }

    public static void setContext(Context mContext) {
        this.mContext = mContext;
    }

    ...

}

In your manifest:

<application
        android:icon="..."
        android:label="..."
        android:name="com.example.yourmainpackagename.App" >
                       class that extends Application ^^^

In Activity B:

public class B extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sampleactivitylayout);

        App.setContext(this);
                  ...
        }
...
}

In class A:

Context c = App.getContext();

Note:

There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.

Caner
  • 57,267
  • 35
  • 174
  • 180
hasanghaforian
  • 13,858
  • 11
  • 76
  • 167
  • 4
    Can I ask why does it need to implement OnInitListener ? – akari Jun 05 '14 at 14:32
  • Alternatively, since your app presumably has a main activity (mine is named `MainActivity`), you could put the static `Context` members in that class. (Merely because you've already made that custom class, so no need to make another class, App.) On the other hand, it is arguably clearer to put stuff in `App` that is not really related to `MainActivity`. – ToolmakerSteve Oct 07 '15 at 22:24
  • 1
    Either way, it is important to ***set the static to null*** when Class B goes away. Otherwise, that Class B instance, which is an activity that may hold lots of resources, will not be GC'd until your app exits. (If Class B is your ***main activity, and you do want to keep it around until your app exits***, then disregard this comment.) – ToolmakerSteve Oct 07 '15 at 22:41
  • 3
    Keeping contexts as static can cause memory leaks in Android. – Marc Bacvanski Jul 26 '16 at 04:31
  • `OnInitListener` that is decalred in `TextToSpeech.OnInitListener`? – János Oct 29 '16 at 14:54
  • `OnInitListener` is not needed, it was probably forgotten. I removed it – Caner Jan 25 '17 at 13:20
38

The best and easy way to get the activity context is putting .this after the name of the Activity. For example: If your Activity's name is SecondActivity, its context will be SecondActivity.this

John Alexander Betts
  • 4,718
  • 8
  • 47
  • 72
  • I wonder what the difference is between this solution and the more complex accepted solution -- if there is a difference at all. – David Gay Feb 07 '18 at 18:31
  • 1
    @DavidGay getApplicationContext returns the context for the entire application, this is no recommended to use, at least you need to get the application context – John Alexander Betts Feb 15 '18 at 21:43
  • @John Alexander Betts Thank you! This should be the accepted answer and should get the highest vote. This is a very simple and straight forward answer that actually answers the OP's question as against complicated, unclear and error-prone hack-like solution that was accepted as answer. – pasignature Jun 17 '20 at 00:50
3

you pass the context to class B in it's constructor, and make sure you pass getApplicationContext() instead of a activityContext()

Shark
  • 6,513
  • 3
  • 28
  • 50
  • 2
    applicationContext and activity context are different, they have different lifespans and you should use it accordingly. – Gan Sep 07 '12 at 15:15
  • @Gan depends what's the point of Class B at all; somehow i just presume that ApplicationContext will be more useful than activity context. but that's just me :) – Shark Sep 07 '12 at 15:17
  • @Shark : The application context is only a partial context and doesn't work for some things in particular UI related operations. – Squonk Sep 07 '12 at 15:28
  • @Squonk can you name a few? I haven't encountered a case where application context fails and activity context doesn't. – Shark Sep 07 '12 at 15:31
  • 2
    @Shark : Sorry, I worded that badly. If the requirement is just to have a `Context` then either the application context or an activity context will work. If, however, the class being passed the context is a 'helper' class that might do UI-related work then `ctx.getWindowManager()` (for example) wouldn't be a valid method call if `ctx` was a reference to the application context. In other words, it really depends on *why* the class needs to be passed a 'context' and what it needs it for. – Squonk Sep 07 '12 at 15:55
  • @Shark you can have a look at http://stackoverflow.com/a/4128799/328947 where the same discussion is on the same context. – Gan Sep 07 '12 at 16:00
1

You can create a constructor using parameter Context of class A then you can use this context.

Context c;

A(Context context){ this.c=context }

From B activity you create a object of class A using this constructor and passing getApplicationContext().

Helal Khan
  • 867
  • 3
  • 10
  • 25
0

If you need the context of A in B, you need to pass it to B, and you can do that by passing the Activity A as parameter as others suggested. I do not see much the problem of having the many instances of A having their own pointers to B, not sure if that would even be that much of an overhead.

But if that is the problem, a possibility is to keep the pointer to A as a sort of global, avariable of the Application class, as @hasanghaforian suggested. In fact, depending on what do you need the context for, you could even use the context of the Application instead.

I'd suggest reading this article about context to better figure it out what context you need.

Thomas
  • 2,751
  • 5
  • 31
  • 52
  • 1
    Since this is a year later than the accepted answer, which already shows in detail how to do this, this shouldn't be a separate answer: The only "new" part is the last sentence, which contains a *useful link*. This would be best as a ***comment*** on the accepted answer. – ToolmakerSteve Oct 07 '15 at 22:36
0

In Kotlin will be :

activity?.applicationContext?.let {
         it//<- you context
        }
Serg Burlaka
  • 2,351
  • 24
  • 35
0

The MainActivity class has those properties you can use:

  • applicationContext
  • baseContext
  • this

See here for differences: difference and when to use getApplication(), getApplicationContext(), getBaseContext() and someClass.this

Ronen Festinger
  • 2,260
  • 1
  • 23
  • 32
0

I dont know who may need this at this point but: @hasanghaforian is correct, and contrary to what @gezdy says here, no, using registerActivityLifecycleCallbacks is not a solution, no matter how you look at the problem, it doesn't even make sense...

One could... maybe create a working version that uses the registerActivityLifecycleCallbacks option but it would be unnecessarily complex and slower.

The aim is to: Proactively retrieve the top most desired Activity.

Now the problem with Hasan's answer and gezdy's answer is that neither acknowledges the fact that, the same way Fragments stack one on top of each other, Activities can ALSO be stacked, so we need a LinkedDeque...

public class ActivityRegistry extends Application {
    private final LinkedList<Activity> activities = new LinkedList<>();
    public<A extends Activity> boolean register(A activity) {
        return !contains(activity) && activities.offerLast(activity);
    }
    public void unregister() {
        activities.pollLast();
    }

    public<A extends Activity> A getLastActivity(Class<A> componentTYpe) {
        Activity current = getLastActivity();
        return componentTYpe.isInstance(current) ? componentTYpe.cast(current) : null;
    }

    public<A extends Activity> boolean contains(A activity) {
        return activities.contains(activity);
    }

    public void clear() {
        activities.clear();
    }

    private Activity getLastActivity() {
        return activities.peekLast();
    }
}

You must take into consideration that the register(A activity) method adds ONLY IF object is NOT PRESENT.

Since BOTH answers are registering Activities during the RESUME phase of the lifecycle, and then unregistering them during the DESTROY. The Registration - Unregistration cycle is NOT a CLOSED LOOP.

This means that if the app goes to the background and then to the foreground again 2 instances will be added, since the RESUMED phase gets called twice without traversing the DESTROY. My solution prevents that, but another alternative is to register during the onCreate() phase of the Activity..

Now as to the "Memory Leak" issue from the Activity perspective.

There is NO NEED to assign the context to a field, IF the context can be accessed from a method, IN FACT, methods are provided precisely to avoid MemLeaks, since, if there would be NO danger of it leaking, the variable could be easily passed via constructor parameter.

This is Gezdy's code:

public class MyBaseActivity extends Activity {
    protected MyApp mMyApp; //This field will create a Memory Leak

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mMyApp = (MyApp)this.getApplicationContext();
        //If app context can be accessed via method, we dont need to assign it to a field.
    }
    protected void onResume() {
        super.onResume();
        mMyApp.setCurrentActivity(this);
    }
    protected void onPause() {
        clearReferences();
        super.onPause();
    }
    protected void onDestroy() {        
        clearReferences();
        super.onDestroy();
    }

    private void clearReferences(){
        Activity currActivity = mMyApp.getCurrentActivity();
        if (this.equals(currActivity))
            mMyApp.setCurrentActivity(null);
    }
}

Instead do this:

public class MyBaseActivity extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        ((ActivityRegistry)getApplicationContext()).register(this);
        super.onCreate(savedInstanceState);
    }

    protected void onDestroy() {        
        ((ActivityRegistry)getApplicationContext()).unregister();
        super.onDestroy();
    }
}

Now the Activity can be retrieved like this:

    MyActivity activity = ((ActivityRegistry)getApplicationContext()).getLastActivity(MyActivity.class);
//If activity returns null, it means the last Activity was NOT of type MyActivity.class.
//If you pass Activity.class instead, it will always get you the last Activity.
//And the you must FORCE CAST into what you believe it to be the type.

Where MyActivity extends MyBaseActivity

Delark
  • 1,141
  • 2
  • 9
  • 15