sirve - obtener actividad android
¿Usando el contexto de la aplicación en todas partes? (10)
Algunas personas han preguntado: ¿cómo puede el singleton devolver un puntero nulo? Estoy respondiendo esa pregunta. (No puedo responder en un comentario porque necesito publicar un código).
Puede devolver nulo entre dos eventos: (1) la clase se carga y (2) se crea el objeto de esta clase. Aquí hay un ejemplo:
class X {
static X xinstance;
static Y yinstance = Y.yinstance;
X() {xinstance=this;}
}
class Y {
static X xinstance = X.xinstance;
static Y yinstance;
Y() {yinstance=this;}
}
public class A {
public static void main(String[] p) {
X x = new X();
Y y = new Y();
System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
}
}
Vamos a ejecutar el código:
$ javac A.java
$ java A
x:X@a63599 y:Y@9036e
x:null y:null
La segunda línea muestra que Y.xinstance y X.yinstance son nulos ; son nulas porque las variables X.xinstance y Y.yinstance se leyeron cuando eran nulas.
¿Se puede arreglar esto? Sí,
class X {
static Y y = Y.getInstance();
static X theinstance;
static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
static X x = X.getInstance();
static Y theinstance;
static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}
public class A {
public static void main(String[] p) {
System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
System.out.println("x:"+Y.x+" y:"+X.y);
}
}
y este código no muestra ninguna anomalía:
$ javac A.java
$ java A
x:X@1c059f6 y:Y@152506e
x:X@1c059f6 y:Y@152506e
PERO esta no es una opción para el objeto de la Application
Android: el programador no controla el momento en que se crea.
Una vez más: la diferencia entre el primer ejemplo y el segundo es que el segundo ejemplo crea una instancia si el puntero estático es nulo. Pero un programador no puede crear el objeto de aplicación de Android antes de que el sistema decida hacerlo.
ACTUALIZAR
Un ejemplo más desconcertante donde los campos estáticos inicializados resultan ser null
.
Main.java :
enum MyEnum {
FIRST,SECOND;
private static String prefix="<", suffix=">";
String myName;
MyEnum() {
myName = makeMyName();
}
String makeMyName() {
return prefix + name() + suffix;
}
String getMyName() {
return myName;
}
}
public class Main {
public static void main(String args[]) {
System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
}
}
Y usted obtiene:
$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull
Tenga en cuenta que no puede mover la declaración de variable estática una línea superior, el código no se compilará.
En una aplicación de Android, ¿hay algún problema con el siguiente enfoque:
public class MyApp extends android.app.Application {
private static MyApp instance;
public MyApp() {
instance = this;
}
public static Context getContext() {
return instance;
}
}
¿Y pasarlo a todas partes (por ejemplo, SQLiteOpenHelper) donde se requiere el contexto (y, por supuesto, sin fugas)?
Clase de aplicación:
import android.app.Application;
import android.content.Context;
public class MyApplication extends Application {
private static Context mContext;
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
public static Context getAppContext() {
return mContext;
}
}
Declara la aplicación en el AndroidManifest:
<application android:name=".MyApplication"
...
/>
Uso:
MyApplication.getAppContext()
En mi experiencia, este enfoque no debería ser necesario. Si necesita el contexto para cualquier cosa, generalmente puede obtenerlo mediante una llamada a View.getContext() y utilizando el Contexto obtenido allí puede llamar a Context.getApplicationContext() para obtener el contexto de la Aplicación. Si está tratando de obtener el contexto de Appication desde una Actividad, siempre puede llamar a Activity.getApplication() que debería poder pasar como el Contexto necesario para una llamada a SQLiteOpenHelper ()
En general, no parece que haya un problema con su enfoque para esta situación, pero cuando se trata de Context, asegúrese de no perder memoria en ningún lugar como se describe en el blog oficial de desarrolladores de Android de Google.
Es un buen enfoque. Yo también lo uso. Solo sugeriría anular onCreate
para establecer el singleton en lugar de usar un constructor.
Y como mencionó SQLiteOpenHelper
: en onCreate ()
también puede abrir la base de datos.
Personalmente creo que la documentación se equivocó al decir que, normalmente, no hay necesidad de subclasificar la aplicación . Creo que lo contrario es cierto: siempre se debe subclasificar la aplicación.
Está intentando crear un contenedor para obtener el contexto de la aplicación y existe la posibilidad de que devuelva el puntero " null
".
Según mi entendimiento, supongo que es un mejor enfoque para llamar a cualquiera de los 2 Context.getApplicationContext()
o Activity.getApplication()
.
Estoy usando el mismo enfoque, sugiero escribir el singleton un poco mejor:
public static MyApp getInstance() {
if (instance == null) {
synchronized (MyApp.class) {
if (instance == null) {
instance = new MyApp ();
}
}
}
return instance;
}
pero no uso en todas partes, uso getContext()
y getApplicationContext()
donde puedo hacerlo!
Hay un par de problemas potenciales con este enfoque, aunque en muchas circunstancias (como su ejemplo) funcionará bien.
En particular, debe tener cuidado al tratar con cualquier cosa que tenga que ver con la GUI
que requiere un Context
. Por ejemplo, si pasa el Contexto de la aplicación a LayoutInflater
, obtendrá una Excepción. En términos generales, su enfoque es excelente: es una buena práctica usar Activity''s
Context
una Activity''s
dentro de esa Activity
y el Application Context
la Application Context
cuando se pasa un contexto más allá del alcance de una Activity
para evitar pérdidas de memoria .
Además, como alternativa a su patrón, puede utilizar el acceso directo de llamar a getApplicationContext()
en un objeto de Context
(como una actividad) para obtener el contexto de la aplicación.
La definición estática del contexto provocará la pérdida de memoria
Forma estándar de obtener contexto en todas partes:
public class App extends Application {
public static transient SoftReference<Context> contextReference;
@Override
public void onCreate() {
super.onCreate();
contextReference = new SoftReference<Context>(getApplicationContext());
}
}
De esta manera, tendrás contexto en cualquier parte del código como este:
App.contextReference.get();
Cualquier otra forma reducirá el rendimiento y causará la pérdida de memoria.
Espero ser útil ...
Me gusta, pero sugeriría un singleton en su lugar:
package com.mobidrone;
import android.app.Application;
import android.content.Context;
public class ApplicationContext extends Application
{
private static ApplicationContext instance = null;
private ApplicationContext()
{
instance = this;
}
public static Context getInstance()
{
if (null == instance)
{
instance = new ApplicationContext();
}
return instance;
}
}
Usaría el contexto de la aplicación para obtener un servicio del sistema en el constructor. Esto facilita las pruebas y los beneficios de la composición.
public class MyActivity extends Activity {
private final NotificationManager notificationManager;
public MyActivity() {
this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE));
}
public MyActivity(NotificationManager notificationManager) {
this.notificationManager = notificationManager;
}
// onCreate etc
}
La clase de prueba usaría el constructor sobrecargado.
Android usaría el constructor por defecto.