¿Qué tiene de malo definir a Handler en forma de una clase interna anónima?

Escribir este blog es para prepararse para el análisis de las fugas de memoria causadas por Handler.

¿Cuál es el significado de clase interna anónima?

La primera es la clase interna, (la clase interna no es difícil de entender, si tiene tiempo para analizarla, no se ampliará aquí) ¿Por qué se llama anónimo? Porque el nombre de la clase no está claramente definido. Basta con mirar el ejemplo a continuación.

Tres casos de clase interna anónima

  • Una clase interna anónima que implementa una interfaz,
    como la que se usa comúnmente en 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.OnClickListenerSolo no se proporciona el nombre de la interfaz, el nombre real de la clase. El método completo de escritura debe ser:

    class TVListener implements View.OnClickListener{
    
    

        @Override
        public void onClick(View v) {
    
    
            System.out.println("onClick");
        }
    }
	
    tv.setOnClickListener(new TVListener());

TVListenerEs el nombre de la clase específica.

  • Una clase interna anónima que hereda una clase abstracta. AsyncTaskImplemente métodos abstractos, como , en Android TimerTask.
  • Una clase interna anónima que hereda de una clase normal. Anular un método común Un ejemplo típico en Android es Handler, que generalmente anula el método handleMessage().
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();
    }
}

¿Por qué las clases internas no estáticas contienen referencias a las clases externas?

Las clases internas estáticas no contienen referencias a clases externas. Verifique en detalle: ¿ Por qué las clases internas no estáticas pueden contener clases externas?
Escribimos tres clases y observamos los archivos .class compilados.

//模拟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();
    }
}

Después de compilar, se generan 4 archivos .class:

Mire MainActivity$1.class, el constructor pasa el objeto MainActivity var1.

class MainActivity$1 extends Handler {
    
    
    MainActivity$1(MainActivity var1) {
    
    
        this.this$0 = var1;
    }

    public void handleMessage() {
    
    
        System.out.println("閲嶅啓handleMessage()鏂规硶");
    }
}

Un poco incierto, si no es una clase interna anónima, sino solo una clase interna no estática, ¿también tendrá una referencia?
intentar:

public class OutClass {
    
    
    class InClass{
    
    

    }
}

Después de la compilación:

mire el archivo OutClass$InnerClass.class:

class OutClass$InClass {
    
    
    OutClass$InClass(OutClass var1) {
    
    
        this.this$0 = var1;
    }
}

Todavía pasó la referencia de la clase externa OutClass en el constructor. Nota: Esto muestra que incluso si no usa una clase interna anónima, use una clase interna de miembro no estático para definir un Controlador, aún mantendrá una referencia a la Actividad. Por lo tanto, solo puede personalizar Handler utilizando una clase interna estática.

Entonces, en el archivo .class de la clase interna no estática, el constructor pasará automáticamente la referencia de la clase externa. Independientemente de si es anónimo o no, siempre que sea una clase interna no estática, contiene una referencia a la clase externa de forma predeterminada.

Supongo que te gusta

Origin blog.csdn.net/zhangjin1120/article/details/131542103
Recomendado
Clasificación