Writing this blog is to prepare for the analysis of memory leaks caused by Handler.
Table of contents
What is the meaning of anonymous inner class?
The first is the inner class, (the inner class is not difficult to understand, if you have time to analyze it, it will not be expanded here) Why is it called anonymous? Because the name of the class is not clearly defined. Just look at the example below.
Three cases of anonymous inner class
- An anonymous inner class that implements an interface,
such as commonly used in androidsetOnClickListener()
,runOnUiThread()
.
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
...
public interface OnClickListener {
void onClick(View v);
}
...
}
//使用:
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
View.OnClickListener
Just the interface name, the real class name, is not given. The complete writing method should be:
class TVListener implements View.OnClickListener{
@Override
public void onClick(View v) {
System.out.println("onClick");
}
}
tv.setOnClickListener(new TVListener());
TVListener
It is the specific class name.
- An anonymous inner class that inherits an abstract class.
AsyncTask
Implement abstract methods, such as , in AndroidTimerTask
. - An anonymous inner class that inherits from a normal class. Override a common method. A typical example in Android is Handler, which generally overrides the handleMessage() method.
public class StandardActivity extends AppCompatActivity {
private static final String TAG = "ActivityA";
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 100) {
Log.i(TAG, "xxx");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate: ");
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
Message msg = new Message();
msg.what = 100;
myHandler.sendMessage(msg);
}
}).start();
}
}
Why do non-static inner classes hold references to outer classes?
Static inner classes do not hold references to outer classes. Check in detail: Why can non-static inner classes hold outer classes?
We write three classes and look at the compiled .class files.
//模拟Android SDK中Activity.java
public class Activity {
}
//模拟Android SDK中的Handler.java
public class Handler {
public void handleMessage(){
}
}
//模拟实际开发中的MainActivity
public class MainActivity extends Activity {
Handler mH;
public void onCreate() {
mH = new Handler() {
@Override
public void handleMessage() {
System.out.println("重写handleMessage()方法");
}
};
System.out.println(mH.getClass().getName());
}
public static void main(String[] args) {
new MainActivity().onCreate();
}
}
After compiling, 4 .class files are indeed generated:
Look at MainActivity$1.class, the constructor does pass in the MainActivity object var1.
class MainActivity$1 extends Handler {
MainActivity$1(MainActivity var1) {
this.this$0 = var1;
}
public void handleMessage() {
System.out.println("閲嶅啓handleMessage()鏂规硶");
}
}
A little uncertain, if it is not an anonymous inner class, but only a non-static inner class, will it also hold a reference?
try:
public class OutClass {
class InClass{
}
}
After compilation:
look at the OutClass$InnerClass.class file:
class OutClass$InClass {
OutClass$InClass(OutClass var1) {
this.this$0 = var1;
}
}
A reference to the external class OutClass is still passed in the constructor. Note: This shows that even if you do not use an anonymous inner class, use a non-static member inner class to define a Handler, it will still hold a reference to the Activity. So you can only customize Handler by using static inner class.
So in the .class file of the non-static inner class, the constructor will automatically pass in the reference of the outer class. Regardless of whether it is anonymous or not, as long as it is a non-static inner class, it holds a reference to the outer class by default.