Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inner classes: Android vs Java

Tags:

java

android

I'm aware that inner classes are not recommended in Android because they hold a reference to the enclosing class. However, in Java, the outer class is only GCed when the inner class is no longer referenced. That means, in Android, provided you have a non-static reference in the outer activity class to the inner class, the inner class cannot exist longer than the outer activity class because the activity can only be destroyed if it doesn't hold a reference to the inner class anymore (at least that is what I'm inferring). So what's the problem using non-static inner classes then (since they can't obviously exist longer than the outer activity if you infer from java)? Am I missing something?

Thanks!

like image 920
OckhamsRazor Avatar asked Apr 11 '12 18:04

OckhamsRazor


2 Answers

Consider this simple example

class Leaker 
{
    public static Object leakedObj;
}

class MyActivity extends Activity
{
     public class MyInnerClass { ... }

     void onCreate(Bundle savedState) 
     {
        Leaker.leakedObj = new MyInnerClass();
        //The activity now won't be GCed until Leaker.leakedObj is cleared.          
     }
}

You can easily pass an inner non-static class outside the context of your activity. As long as you don't pass your inner class to objects outside of your Activity's lifecycle you should be okay. But it certainly IS possible to leak your activity via an inner class.

like image 129
Justin Breitfeller Avatar answered Nov 04 '22 09:11

Justin Breitfeller


I won't bother paraphrasing, because Google can explain it better.

Assuming: Parent class is Foo and inner class is Foo$Inner:

The problem is that the VM considers direct access to Foo's private members from Foo$Inner to be illegal because Foo and Foo$Inner are different classes, even though the Java language allows an inner class to access an outer class' private members. To bridge the gap, the compiler generates a couple of synthetic methods:

/*package*/ static int Foo.access$100(Foo foo) {
    return foo.mValue;
}
/*package*/ static void Foo.access$200(Foo foo, int value) {
    foo.doStuff(value);
}

The inner class code calls these static methods whenever it needs to access the mValue field or invoke the doStuff method in the outer class. What this means is that the code above really boils down to a case where you're accessing member fields through accessor methods. Earlier we talked about how accessors are slower than direct field accesses, so this is an example of a certain language idiom resulting in an "invisible" performance hit.

If you're using code like this in a performance hotspot, you can avoid the overhead by declaring fields and methods accessed by inner classes to have package access, rather than private access. Unfortunately this means the fields can be accessed directly by other classes in the same package, so you shouldn't use this in public API.

Source: https://developer.android.com/training/articles/perf-tips.html#PackageInner

like image 28
edthethird Avatar answered Nov 04 '22 11:11

edthethird