Estudio de Android:
No coloque clases de contexto de Android en campos estáticos; esto es una pérdida de memoria (y también rompe Instant Run)
Entonces, 2 preguntas:
# 1 ¿Cómo se llama a startService
desde un método estático sin una variable estática para el contexto?
# 2 ¿Cómo se envía una transmisión local desde un método estático (mismo)?
Ejemplos:
public static void log(int iLogLevel, String sRequest, String sData) {
if(iLogLevel > 0) {
Intent intent = new Intent(mContext, LogService.class);
intent.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
mContext.startService(intent);
}
}
o
Intent intent = new Intent(MAIN_ACTIVITY_RECEIVER_INTENT);
intent.putExtra(MAIN_ACTIVITY_REQUEST_FOR_UPDATE, sRequest));
intent.putExtra(MAIN_ACTIVITY_DATA_FOR_VIEW, sData);
intent.putExtra(MAIN_ACTIVITY_LOG_LEVEL, iLogLevel);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
¿Cuál sería la forma correcta de hacer esto sin usar mContext
?
NOTA: Creo que mi pregunta principal podría ser cómo pasar contexto a una clase de la que vive el método de llamada.
android
android-studio-2.2
John Smith
fuente
fuente
Respuestas:
Simplemente páselo como parámetro a su método. No tiene sentido crear una instancia estática de
Context
únicamente con el propósito de iniciar unIntent
.Así es como debería verse su método:
public static void log(int iLogLevel, String sRequest, String sData, Context ctx) { if(iLogLevel > 0) { Intent intent = new Intent(ctx, LogService.class); intent1.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW"); ctx.startService(intent); } }
Actualización a partir de los comentarios sobre la pregunta: Conecte en cascada el contexto desde la actividad de inicio (a través de parámetros de constructor o parámetros de método) hasta el punto en que lo necesite.
fuente
MyClass
agregue un constructor público como un métodopublic MyClass(Context ctx) { // put this ctx somewhere to use later }
(Este es su constructor) Ahora cree una nueva instancia deMyClass
uso de este constructor, por ejemploMyClass mc = new MyClass(ctx);
Solo asegúrese de pasar context.getApplicationContext () o llamar a getApplicationContext () en cualquier contexto que se pase a través de métodos / constructor a su singleton si decide almacenarlo en cualquier campo miembro.
ejemplo a prueba de idiotas (incluso si alguien pasara una actividad, tomará el contexto de la aplicación y lo usará para crear una instancia del singleton):
public static synchronized RestClient getInstance(Context context) { if (mInstance == null) { mInstance = new RestClient(context.getApplicationContext()); } return mInstance; }
getApplicationContext () de acuerdo con los documentos: "Devuelve el contexto del único objeto de aplicación global del proceso actual".
Significa que el contexto devuelto por "getApplicationContext ()" vivirá durante todo el proceso y, por lo tanto, no importa si almacena una referencia estática en cualquier lugar, ya que siempre estará allí durante el tiempo de ejecución de su aplicación (y sobrevivirá a cualquier objeto / singletons instanciados por él).
Compare eso con el contexto dentro de las vistas / actividades que contienen grandes cantidades de datos, si filtra un contexto contenido por una actividad, el sistema no podrá liberar ese recurso que obviamente no es bueno.
Una referencia a una actividad por su contexto debe vivir el mismo ciclo de vida que la actividad en sí; de lo contrario, mantendrá el contexto como rehén y provocará una pérdida de memoria (que es la razón detrás de la advertencia de pelusa).
EDITAR: Para el tipo que critica el ejemplo de los documentos anteriores, incluso hay una sección de comentarios en el código sobre lo que acabo de escribir:
// getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in.
fuente
Es solo una advertencia. No se preocupe. Si desea utilizar un contexto de aplicación, puede guardarlo en una clase "singleton", que se utiliza para guardar todas las clases singleton en su proyecto.
fuente
En tu caso no tiene mucho sentido tenerlo como campo estático pero no creo que sea malo en todos los casos. Si sabe qué está haciendo ahora, puede tener un campo estático que tenga contexto y anularlo más tarde. Estoy creando una instancia estática para mi clase de modelo principal que tiene contexto dentro, su contexto de aplicación, no contexto de actividad y también tengo un campo de instancia estática de clase que contiene Actividad en la que anulo al destruir. No veo que tenga pérdida de memoria. Entonces, si algún tipo inteligente piensa que estoy equivocado, no dude en comentar ...
También Instant Run funciona bien aquí ...
fuente
Generalmente, evite tener campos de contexto definidos como estáticos. La advertencia en sí misma explica por qué: es una pérdida de memoria. Sin embargo, romper la ejecución instantánea puede no ser el mayor problema del planeta.
Ahora, hay dos escenarios en los que recibiría esta advertencia. Por ejemplo (el más obvio):
public static Context ctx;
Y luego está el un poco más complicado, donde el contexto está envuelto en una clase:
public class Example{ public Context ctx; //Constructor omitted for brievety }
Y esa clase se define como estática en algún lugar:
public static Example example;
Y recibirás la advertencia.
La solución en sí es bastante simple: no coloque campos de contexto en instancias estáticas , ya sea de una clase envolvente o declarándola estática directamente.
Y la solución a la advertencia es simple: no coloque el campo estáticamente. En su caso, pase el contexto como una instancia al método. Para las clases en las que se realizan múltiples llamadas de contexto, use un constructor para pasar el contexto (o una Actividad para el caso) a la clase.
Tenga en cuenta que es una advertencia, no un error. Si por alguna razón necesita un contexto estático, puede hacerlo. Aunque crea una pérdida de memoria cuando lo hace.
fuente
Si se asegura de que sea un contexto de aplicación. No importa. Agrega esto
@SuppressLint("StaticFieldLeak")
fuente
Úselo
WeakReference
para almacenar el contexto en clases Singleton y la advertencia desapareceráprivate WeakReference<Context> context; //Private contructor private WidgetManager(Context context) { this.context = new WeakReference<>(context); } //Singleton public static WidgetManager getInstance(Context context) { if (null == widgetManager) { widgetManager = new WidgetManager(context); } return widgetManager; }
Ahora puede acceder al contexto como
if (context.get() instanceof MainActivity) { ((MainActivity) context.get()).startActivityForResult(pickIntent, CODE_REQUEST_PICK_APPWIDGET); }
fuente