Recibo una advertencia en mi código que dice:
Esta clase AsyncTask debe ser estática o pueden producirse fugas (anónimo android.os.AsyncTask)
La advertencia completa es:
Esta clase AsyncTask debería ser estática o podrían producirse fugas (android.os.AsyncTask anónimo) Un campo estático filtrará contextos. Las clases internas no estáticas tienen una referencia implícita a su clase externa. Si esa clase externa es, por ejemplo, un Fragmento o Actividad, entonces esta referencia significa que el manejador / cargador / tarea de larga duración mantendrá una referencia a la actividad que evita que se recolecte basura. Del mismo modo, las referencias directas de campo a actividades y fragmentos de estas instancias de ejecución más prolongada pueden causar fugas. Las clases ViewModel nunca deben apuntar a Vistas o Contextos que no sean de aplicación.
Este es mi código:
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
¿Cómo corrijo esto?
fuente
myActivity.getApplication()
en el constructor privado para Singleton, para inicializar las clases RoomDB y otras clases). Mis ViewModels obtienen la instancia Singleton como referencia privada para realizar algunas operaciones en la base de datos. Entonces, los ViewModels importan el paquete Singleton, así como tambiénandroid.app.Application
uno de ellosandroid.app.Activity
. Dado que "the Singleton" no necesita importar esos ViewModels para que funcionen, aun así, ¿podrían ocurrir pérdidas de memoria?Respuestas:
Las clases internas no estáticas contienen una referencia a la clase que lo contiene. Cuando declaras
AsyncTask
como una clase interna, puede vivir más tiempo que laActivity
clase que lo contiene . Esto se debe a la referencia implícita a la clase que lo contiene. Esto evitará que la actividad se recolecte basura, por lo tanto, la pérdida de memoria.Para resolver su problema, use la clase anidada estática en lugar de la clase anónima, local e interna o use la clase de nivel superior.
fuente
Cómo usar una clase AsyncTask interna estática
Para evitar fugas, puede hacer que la clase interna sea estática. El problema con eso, sin embargo, es que ya no tiene acceso a las vistas de UI de la Actividad o las variables miembro. Puede pasar una referencia al
Context
pero luego corre el mismo riesgo de una pérdida de memoria. (Android no puede recolectar basura de la Actividad una vez que se cierra si la clase AsyncTask tiene una fuerte referencia a ella). La solución es hacer una referencia débil a la Actividad (o loContext
que sea que necesite).Notas
AsyncTask
tutoriales principales aún no se tratan (ver aquí , aquí , aquí y aquí ).AsyncTask
fuera una clase de nivel superior. Una clase interna estática es básicamente lo mismo que una clase de nivel superior en Java.Si no necesita la Actividad en sí pero aún desea el Contexto (por ejemplo, para mostrar a
Toast
), puede pasar una referencia al contexto de la aplicación. En este caso, elAsyncTask
constructor se vería así:Kotlin
En Kotlin simplemente no incluya la
inner
palabra clave para la clase interna. Esto lo hace estático por defecto.fuente
onPostExecute
método de nuevo en el código de seguridad. Puedes ver que actualicé la interfaz de usuarioTextView
allí. Solo useactivity.findViewById
para obtener una referencia a cualquier elemento de la interfaz de usuario que necesite actualizar.activity.isFinishing()
cheque y posiblemente lo reemplazaría con unfragment.isRemoving()
cheque. Sin embargo, no he trabajado mucho con fragmentos recientemente.AsyncTask
constructor pasas una referencia a tu clase externa. Y endoInBackground()
usted puede obtener una referencia a la clase externa conMyOuterClass ref = classReference.get()
. Compruebe si haynull
. (2) EnonPostExecute()
solo está actualizando la interfaz de usuario con los resultados de la tarea en segundo plano. Es como en cualquier otro momento que actualiza la interfaz de usuario. La comprobaciónactivity.isFinishing()
es solo para asegurarse de que la actividad aún no ha comenzado a finalizar, en cuyo caso no tendría sentido actualizar la interfaz de usuario.Esta
AsyncTask
clase debe ser estática o se pueden producir fugas porqueActivity
se destruye,AsyncTask
(ambosstatic
onon-static
) siguen ejecutándosenon-static
(AsyncTask
), tendrá referencia a la clase externa (Activity
).Garbage Collected
lo liberará. Si un objeto no se usa yGarbage Collected
no puede liberarlo => pérdida de memoria=> Si
AsyncTask
es asínon-static
,Activity
no se lanzará el evento se destruye => fugaSolución para actualizar la interfaz de usuario después de hacer AsyncTask como clase estática sin fugas
1) Usar
WeakReference
como respuesta @Suragch2) Enviar y eliminar
Activity
referencias a (desde)AsyncTask
fuente
onDestroy()
no se garantiza que se llame cada vez