Pregunta

En una aplicación para Android, ¿hay algo malo 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 por todas partes (por ejemplo SQLiteOpenHelper) cuando se requiera el contexto (y sin fugas por supuesto)?

¿Fue útil?

Solución

Hay un par de posibles problemas con este enfoque, aunque en muchas circunstancias (como el ejemplo) va a funcionar bien.

En particular, se debe tener cuidado cuando se trata de cualquier cosa que se ocupa de la GUI que requiere una Context . Por ejemplo, si pasa el contexto de aplicación en el LayoutInflater obtendrá una excepción. En términos generales, el enfoque es excelente: es una buena práctica usar un Activity's Context dentro de ese Activity y Application Context cuando se pasa de un contexto más allá de la alcance de un Activity evitar pérdidas de memoria .

Además, como un alternativa a su patrón se puede utilizar el método abreviado de llamar getApplicationContext() en un Context objeto (como una actividad) para obtener el contexto de aplicación.

Otros consejos

En mi experiencia de este enfoque no debería ser necesario. Si necesita el contexto para lo que por lo general puede conseguir a través de una llamada a View.getContext () y utilizando el Context obtenido en ella se puede llamar Context.getApplicationContext () para obtener el contexto Application. Si usted está tratando de obtener el contexto Application esto desde un Activity siempre puede llamar Activity.getApplication () que debe ser capaz de pasar como el Context necesario para una llamada a SQLiteOpenHelper().

En general no parece ser un problema con el enfoque de esta situación, pero cuando se trata de Context sólo asegúrese de que no tengan fugas de memoria en cualquier lugar como se describe en la página oficial Google Android Blog de desarrolladores .

Algunas personas han preguntado:? ¿cómo puede el singleton devolver un puntero nulo Estoy respondiendo a esa pregunta. (No puedo responder en un comentario porque necesito el código postal.)

Se puede devolver null en entre dos eventos: (1) se carga la clase, y (2) se crea el objeto de esta clase. He aquí 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 nula ; que son nulos porque las variables X.xinstance ans Y.yinstance se leyeron cuando eran nulas.

¿Puede ser fijo? 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

y esta no es una opción para el objeto 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, se crea una instancia si el puntero estática es nulo. Sin embargo, un programador no puede crear la objeto de la aplicación de Android antes de que el sistema decide hacerlo.

Actualizar

Un ejemplo más desconcertante donde los campos estáticos inicializados pasar a 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 se obtiene:

$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull

Tenga en cuenta que no se puede mover la variable declaración de una línea estática superior, el código no se compilará.

Usted está tratando de crear un contenedor para obtener contexto de aplicación y hay una posibilidad de que pudiera volver "null" puntero.

Según mi entendimiento, que supongo que es mejor enfoque a CALL cualquiera de los 2 Context.getApplicationContext() o Activity.getApplication().

Clase 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;
    }

}

Declarar la aplicación en el AndroidManifest:

<application android:name=".MyApplication"
    ...
/>

Uso:

MyApplication.getAppContext()

Es un buen enfoque. Yo lo uso yo también. Me gustaría sugerir para anular onCreate para establecer el singleton en lugar de utilizar un constructor.

Y ya que ha mencionado SQLiteOpenHelper:. En onCreate () puede abrir la base de datos, así

En lo personal creo que la documentación se equivocó al decir que Normalmente no hay necesidad de una subclase de aplicación . Creo que es todo lo contrario: debe siempre Aplicación subclase

.

Me gustaría utilizar contexto de 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

}

clase de prueba sería entonces utilizar el constructor sobrecargado.

Android usaría el constructor por defecto.

Me gusta, pero yo sugeriría un producto único 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;
    }
}

Estoy utilizando 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 estoy usando todas partes, yo uso getContext() y getApplicationContext() donde puedo hacerlo!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top