2

I read many posts (one is this) and articles according to which you shouldn't pass context from an Activity to a non activity class, to avoid leak of memory.

I have to use the method findViewById() in a non activity class. So far,I did this:

    public class Text{

        Activity activity;

        public Text(Activity activity){
           this.activity = activity;
        }

        public TextView getMyTextView(){
           return activity.findViewById(R.id.textView1)
        }

    }

Now I'm wondering if even "passing" an Activity can lead to a memory leak. What's the best way to be able to call, for example, the method findViewById in a non activity class.

Community
  • 1
  • 1
MDP
  • 4,177
  • 21
  • 63
  • 119
  • 2
    Why pass the Activity and not the TextView? Why even pass any view? The databinding library would map a String directly into a TextView without findViewById – OneCricketeer Jan 28 '17 at 18:37
  • 1
    Even tho I don't see the purpose of such thing, I would recommend to wrap your activity in a weakReference. So when the activity is destroyed you'll get a null value, ofc you need to check if it's null every time you make use of that ref but it'll make sure you're not leaking anything. – Anis LOUNIS aka AnixPasBesoin Jan 28 '17 at 19:03
  • Thank everybody for the help :) – MDP Feb 01 '17 at 08:56

2 Answers2

4

The only thing which can lead to memory leak is misunderstanding of how GC works. The basic rule of avoiding memory leak is to make sure that objects which should be collected by GC are disconnected from GC Root:

enter image description here

There're set of GC roots, and one of them is static field. So, if you assign your activity to such field then GC could not collect it:

class ActivityRef {

 public static Activity ref;

 public static void setActivity(Activity activity){
    ActivityRef.ref = activity;
 }
}

And this activity(with all views, bitmaps and all connected objects) will remain in memory until the app is not killed by system.

Another GC root is Thread.

class SomeThread extends Thread{

  Activity ref;

  public void setActivity(Activity activity){
    this.ref = activity;
  }
}

While thread is alive GC can't collect activity instance.

Therefore there is no best way or method to call findViewById which allows you to avoid memory leak, there is memory model which describes how GC works, if you follow these rules you will never have memory leaks. More here.

Good articles about WeakReferences:

eleven
  • 6,779
  • 2
  • 32
  • 52
  • 3
    Better to use a weak reference to an Activity class – OneCricketeer Jan 28 '17 at 18:35
  • 2
    @cricket_007 I don't think so. WeakReferences just spoil the code with null checks and extra logic. Here good thoughts about WeakReferences: https://medium.com/google-developer-experts/weakreference-in-android-dd1e66b9be9d#.8nk16vpoo https://medium.com/google-developer-experts/finally-understanding-how-references-work-in-android-and-java-26a0d9c92f83#.gry925pel – eleven Jan 28 '17 at 18:38
  • 2
    Perhaps, but I've read posts like don't store Activity references in Asynctask, for example. Just seems like a bad design to need a UI element from a model / utility class – OneCricketeer Jan 28 '17 at 18:39
  • Thank everybody for the help :) – MDP Feb 01 '17 at 08:57
1

Rather then passing the activity reference pass it the views that are necessary. Make sure that the "Non-Activity" class reference is created after your activity class is invoked and release the reference (nonActivityReference = null) before destroying your activity.

Anko6
  • 41
  • 1
  • 9