0

I have a very large project that happens to need to be able to access the Activity Context regularly outside of the Activity class, of which there will only ever be a single instance. I've done a lot of research trying to hammer out the code but there doesn't seem to be a good clean way to access the context and/or activity when needed. It can't be stored in other classes and it shouldn't passed around, as both can cause memory leaks. But can the context and a reference to the activity be stored statically within the activity class itself? If the activity is destroyed, the context/reference will go away too, so there shouldn't be a problem, just like how it would if the application context were stored... is this right?

My main issue is that I have hundreds if not thousands of random objects such as textures, sprites, meshes, scripts, and whatnot, that not only need the context at times (such as loading and renedring), but they need to be preserved/reconstructed across configuration state changes and such using ViewModel, and I want to preserve the object-oriented nature and not put everything in one place (ie, the activity). Most of the data I want to store is Model data and not View data, so keeping it in View breaks the whole OO model of separation. So I'm trying to make each class life-cycle aware, but I need the activity reference to do it:

public class RendererActivity extends AppCompatActivity
{
    static Context activityContex = null;
    static RendererActivity activityReference = null;

    ...

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);    
        activityContext = this;
        activityReference = this;
    }
}


class Texture
{
    static List textureList = null;

    Texture( )
    {
        // check if list allocated
        if(textureList == null) textureList = ViewModelProviders.of(RendererActivity.ActivityReference).get(Texture.List.class);
        ...
    }

    public class List extends ViewModel
    {
        ...
    }
}        

This seems to work perfectly and keeps the OO model clean. I just don't know it it's a good thing to do under the Android framework. I haven't noticed any memory leaks, but it's the potential issues I'm worried about. Any ideas and/or suggestions would be much appreciated.

Michael
  • 1
  • 2
  • Don't use `static` with `this` like never ever, the cases where that's a good idea is really small. Pass a reference to `Texture`, e.g. in the constructor, `Texture(Context context)` and make sure you don't store `Texture` in a static variable (like `textureList`) either because that would be the same leak just more indirect. The rule is really to avoid `static` unless you store something that is okay to leak. – zapl Oct 28 '18 at 09:17
  • I had been passing the context into constructors and such, but read in several places that it could cause leaks, so I changed it. Passing the context to the constructor still doesn't solve the problem that the method that calls the constructor needs to have the context int he first place in order to pass it, and it is not created in the View, as it must be done on the GLES2 thread and not the UI thread. Are there any ways around that problem? I know there have been a lot of requests to Google to add functionality to simply get a reference to the current View, but no luck there. – Michael Oct 28 '18 at 11:26
  • Yes but `static` is worse. Every time you store a reference to an object in some other place you can create a leak if that other place exists longer than the thing referenced since it prevents garbage collection. This is especially critical for `Context` in android since it keeps a whole bunch of big GUI graphics objects in memory. However, when you do it right, i.e. you recreate all objects derived from context every time you get a new context and you never use static (and be careful with threads) you're pretty safe. Usually all UI elements need to be redone each time there is a new context. – zapl Oct 28 '18 at 23:13
  • A few things can be derived off the application context which is safe to keep around forever since it is alive as long as the app process exists and no object can outlive it. But that's limited to usually non-ui items since application context does not know about the current configuration (theme, screen size, ...) (see https://possiblemobile.com/2013/06/context/ or https://medium.com/@ali.muzaffar/which-context-should-i-use-in-android-e3133d00772c for some hints about the differences). It's okay if you need to access your private app dirs, the database, ... things that don't change with config – zapl Oct 28 '18 at 23:18
  • Thank you, I'll keep all that in mind. I'll definitely make my lists non-static objects from now on. But shouldn't storing a static reference to one's self be okay? It is okay for an Application context... though I realize it's a bit special. – Michael Oct 29 '18 at 04:04
  • One last question on this, in case anyone knows... If a class contains a static element, is it the class instance itself or the data elements referenced by the static element (or both) that aren't GC'd? If it's the data elements, I can move them out of the static reference myself when needed. If it's the class instance itself, well, then, for instance, having a static reference inside a View shouldn't be a problem because it will be destroyed and recreated, so there shouldn't be an issue as long as there are no references to anything that might outlive it due to not being GC'd. – Michael Oct 29 '18 at 18:27
  • Classes are not(+) GC'd because they are never(+) unloaded and there is a chain of references from the system class loader (which is a [gc root](https://stackoverflow.com/q/27186799/995891)(see for +)) to them. `static` fields exist as long as their class is loaded and so effectively nothing that is referenced by a `static` field will ever get GC'd. That's why `static` is so bad. If there are just non-static refs, you'll end up with is a giant network of (circular) references which has one bond to a gc root, but that bond breaks e.g. at activity destruction and the whole network can get gc'd – zapl Oct 29 '18 at 20:16
  • Thank you. That clarifies everything. I think the (true) answer to my original question then, is that static references should be nullified whenever the app is paused, etc, and recreated when the app come back, in order to eliminate memory leaks due to object lifetimes. That is very doable. – Michael Oct 30 '18 at 04:03
  • You could do that but it's still not without issues. The biggest problem is that the is only 1 static field and possibly multiple instances of the same activity class at the same time. E.g. you could implement a file browser by starting the same activity with a different folder to display. The same can happen when you have multiple [tasks with their own backstack](https://developer.android.com/guide/components/activities/tasks-and-back-stack). There shouldn't be more than one instance that is active, i.e. not in stopped state but a context is valid during that time, just not after `onDestroy` – zapl Oct 30 '18 at 08:15
  • Yes, it could be a potential problem if done wrong. In this case, there will only be a single instance of the activity ever, so it should be okay. I've eliminated all but 2 static fields, which I set to null in the onPause() method of the activity class, so they should never leak. Thank you again. You have have very helpful. – Michael Oct 30 '18 at 21:09

0 Answers0