Pergunta

Em um aplicativo Android, há de errado nada com a seguinte abordagem:

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

e passá-lo em todos os lugares (por exemplo SQLiteOpenHelper) onde o contexto é necessário (e que não tem fugas é claro)?

Foi útil?

Solução

Há um par de potenciais problemas com esta abordagem, embora em muitas circunstâncias (como o seu exemplo) ele vai funcionar bem.

Em particular, você deve ter cuidado ao lidar com qualquer coisa que lida com o GUI que requer um Context . Por exemplo, se você passar o contexto de aplicação para o LayoutInflater você receberá uma exceção. De um modo geral, a sua abordagem é excelente: é uma boa prática para usar um Activity's Context dentro desse Activity e Application Context quando passa um contexto para além da escopo de uma vazamentos de memória Activity Evitar .

Além disso, como um alternativa para o seu padrão que você pode usar o atalho de getApplicationContext() chamando em um Context objeto (como uma Atividade) para obter o contexto da aplicação.

Outras dicas

Na minha experiência não deve ser necessária esta abordagem. Se você precisar o contexto para qualquer coisa que você normalmente pode obtê-lo através de uma chamada para View.getContext () e usando o Context obtido lá você pode chamar Context.getApplicationContext () para obter o contexto Application. Se você está tentando obter o contexto Application isso a partir de um Activity você pode sempre chamar Activity.getApplication () que deve ser capaz de ser transmitido como o Context necessário para uma chamada para SQLiteOpenHelper().

No geral não parece ser um problema com a sua abordagem para esta situação, mas quando se lida com Context apenas certifique-se que você não está vazando em qualquer lugar de memória como descrito no site oficial Google Android Developers Blog .

Algumas pessoas perguntaram:? como pode o singleton retornar um ponteiro nulo Eu estou respondendo a essa pergunta. (Eu não posso responder em um comentário porque eu preciso código postal.)

Pode retornar nulo entre dois eventos: (1) a classe é carregada, e (2) o objecto desta classe é criada. Aqui está um exemplo:

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 executar o código:

$ javac A.java 
$ java A
x:X@a63599 y:Y@9036e
x:null y:null

A segunda linha mostra que Y.xinstance e X.yinstance nulo ; eles são nulos porque as variáveis ?? X.xinstance ans Y.yinstance foram lidos quando eles foram nulos.

Isso pode ser corrigido? Sim,

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

e shows este código nenhuma anomalia:

$ javac A.java 
$ java A
x:X@1c059f6 y:Y@152506e
x:X@1c059f6 y:Y@152506e

MAS isso não é uma opção para o objeto Application Android:. O programador não controla o momento em que é criado

Mais uma vez: a diferença entre o primeiro exemplo e o segundo é que o segundo exemplo, se cria uma instância do ponteiro estático é nula. Mas um programador não pode criar o objeto de aplicativo Android antes que o sistema decide fazê-lo.

Atualizar

Um exemplo mais intrigante, onde campos estáticos inicializados acontecer de 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());
    }
}

E você tem:

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

Note que você não pode mover a variável estática declaração uma linha superior, o código não será compilado.

Você está tentando criar um wrapper para obter contexto de aplicativos e há uma possibilidade de que ele pode retornar "null" ponteiro.

De acordo com o meu entendimento, eu acho que é melhor abordagem para call qualquer um dos 2 Context.getApplicationContext() ou Activity.getApplication().

Aplicação Classe:

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 o pedido na AndroidManifest:

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

Uso:

MyApplication.getAppContext()

É uma boa abordagem. Eu usá-lo mesmo assim. Gostaria de sugerir para substituir onCreate para definir o singleton em vez de usar um construtor.

E já que você mencionou SQLiteOpenHelper:. Em onCreate () você pode abrir o banco de dados, bem

Pessoalmente acho que a documentação entendeu errado em dizer que Normalmente, não há necessidade de Aplicação subclasse . Eu acho que o oposto é verdadeiro: Você deve sempre Aplicação subclasse

.

Gostaria de usar Aplicação Contexto para obter um serviço de sistema no construtor. Isso facilita Teste e benefícios da composição

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

}

classe de teste, então, usar o construtor sobrecarregado.

Android usaria o construtor padrão.

Eu gosto dele, mas gostaria de sugerir um singleton em vez disso:

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

Eu estou usando a mesma abordagem, sugiro para escrever o singleton um pouco melhor:

public static MyApp getInstance() {

    if (instance == null) {
        synchronized (MyApp.class) {
            if (instance == null) {
                instance = new MyApp ();
            }
        }
    }

    return instance;
}

mas eu não estou usando em todos os lugares, eu uso getContext() e getApplicationContext() onde posso fazê-lo!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top