What's wrong with defining Handler in the form of an anonymous inner class?

Writing this blog is to prepare for the analysis of memory leaks caused by Handler.

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 android setOnClickListener(), 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.OnClickListenerJust 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());

TVListenerIt is the specific class name.

  • An anonymous inner class that inherits an abstract class. AsyncTaskImplement abstract methods, such as , in Android TimerTask.
  • 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.

Guess you like

Origin blog.csdn.net/zhangjin1120/article/details/131542103