Eu escrevi essa resposta em '09, quando o Android era relativamente novo, e havia muitas áreas não bem estabelecidas no desenvolvimento do Android. Eu adicionei um longo adendo no final deste post, abordando algumas críticas e detalhando um desacordo filosófico que tenho com o uso de Singletons em vez de subclassificar Application. Leia por sua conta e risco.
RESPOSTA ORIGINAL:
O problema mais geral que você está enfrentando é como salvar o estado em várias Atividades e em todas as partes do seu aplicativo. Uma variável estática (por exemplo, um singleton) é uma maneira Java comum de conseguir isso. Descobri, no entanto, que uma maneira mais elegante no Android é associar seu estado ao contexto do aplicativo.
Como você sabe, cada Atividade também é um Contexto, que são informações sobre seu ambiente de execução no sentido mais amplo. Seu aplicativo também possui um contexto, e o Android garante que ele existirá como uma instância única no aplicativo.
A maneira de fazer isso é criar sua própria subclasse de android.app.Application e especificar essa classe na tag do aplicativo em seu manifesto. Agora, o Android criará automaticamente uma instância dessa classe e a disponibilizará para todo o aplicativo. Você pode acessá-lo context
usando qualquer Context.getApplicationContext()
método ( Activity
também fornece um método getApplication()
que tem exatamente o mesmo efeito). A seguir, é apresentado um exemplo extremamente simplificado, com ressalvas a seguir:
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
Isso tem essencialmente o mesmo efeito que o uso de uma variável estática ou singleton, mas integra-se muito bem à estrutura Android existente. Observe que isso não funcionará entre processos (seu aplicativo deve ser um dos raros que possui vários processos).
Algo a ser observado no exemplo acima; suponha que tivéssemos feito algo como:
class MyApp extends Application {
private String myState = /* complicated and slow initialization */;
public String getState(){
return myState;
}
}
Agora, essa inicialização lenta (como bater no disco, bater na rede, bloquear qualquer coisa etc.) será executada toda vez que o Aplicativo for instanciado! Você pode pensar, bem, isso é apenas uma vez para o processo e eu vou ter que pagar o custo de qualquer maneira, certo? Por exemplo, como Dianne Hackborn menciona abaixo, é perfeitamente possível que seu processo seja instanciado - apenas - para manipular um evento de transmissão em segundo plano. Se o seu processamento de transmissão não precisar desse estado, você potencialmente acabou de executar uma série de operações complicadas e lentas por nada. Instanciação preguiçosa é o nome do jogo aqui. A seguir, é uma maneira um pouco mais complicada de usar o Aplicativo, que faz mais sentido para qualquer coisa, exceto o mais simples dos usos:
class MyApp extends Application {
private MyStateManager myStateManager = new MyStateManager();
public MyStateManager getStateManager(){
return myStateManager ;
}
}
class MyStateManager {
MyStateManager() {
/* this should be fast */
}
String getState() {
/* if necessary, perform blocking calls here */
/* make sure to deal with any multithreading/synchronicity issues */
...
return state;
}
}
class Blah extends Activity {
@Override
public void onCreate(Bundle b){
...
MyStateManager stateManager = ((MyApp)getApplicationContext()).getStateManager();
String state = stateManager.getState();
...
}
}
Embora eu prefira a subclassificação de aplicativos a usar singletons aqui como a solução mais elegante, prefiro que os desenvolvedores usem singletons, se realmente necessário, em vez de não pensarem nas implicações de desempenho e multithreading da associação de estado à subclasse de aplicativos.
NOTA 1: Também conforme comentado pelo anticafe, para vincular corretamente a substituição do seu aplicativo ao seu aplicativo, é necessária uma marca no arquivo de manifesto. Mais uma vez, consulte os documentos do Android para mais informações. Um exemplo:
<application
android:name="my.application.MyApp"
android:icon="..."
android:label="...">
</application>
NOTA 2: O usuário608578 pergunta abaixo como isso funciona com o gerenciamento dos ciclos de vida do objeto nativo. Não tenho a menor velocidade para usar o código nativo com o Android nem um pouco e não estou qualificado para responder como isso iria interagir com a minha solução. Se alguém tiver uma resposta para isso, estou disposto a creditá-lo e colocar as informações neste post para obter visibilidade máxima.
TERMO ADITIVO:
Como algumas pessoas observaram, essa não é uma solução para o estado persistente , algo que talvez eu devesse ter enfatizado mais na resposta original. Ou seja, isso não pretende ser uma solução para salvar o usuário ou outras informações que devem persistir durante a vida útil do aplicativo. Portanto, considero a maioria das críticas abaixo relacionadas a aplicativos sendo mortos a qualquer momento, etc ..., discutíveis, pois tudo o que for necessário persistir no disco não deve ser armazenado por meio de uma subclasse de aplicativo. Ele deve ser uma solução para armazenar temporariamente, o estado de aplicativo recriável facilmente (se um usuário está conectado, por exemplo) e componentes que são de instância única (gerente de rede de aplicativos, por exemplo) ( NÃO singleton!) Na natureza.
Dayerman teve a gentileza de apontar uma conversa interessante com Reto Meier e Dianne Hackborn, na qual o uso de subclasses de aplicativos é desencorajado em favor dos padrões de Singleton. Somatik também apontou algo dessa natureza anteriormente, embora eu não o visse na época. Devido aos papéis de Reto e Dianne na manutenção da plataforma Android, não posso de boa fé recomendar ignorar seus conselhos. O que eles dizem, vai. Desejo discordar das opiniões expressas em relação à preferência das subclasses de Singleton em vez de Application. Na minha discordância, usarei os conceitos melhor explicados nesta explicação do StackExchange do padrão de design Singleton, para que eu não precise definir termos nesta resposta. É altamente recomendável que você escaneie o link antes de continuar. Ponto por ponto:
Dianne declara: "Não há motivo para subclassificar do Aplicativo. Não é diferente de criar um singleton ..." Essa primeira afirmação está incorreta. Existem duas razões principais para isso. 1) A classe Application fornece uma garantia vitalícia melhor para um desenvolvedor de aplicativos; é garantido que tenha a vida útil do aplicativo. Um singleton não está EXPLICITAMENTE vinculado ao tempo de vida do aplicativo (embora seja efetivamente). Isso pode não ser um problema para o desenvolvedor de aplicativos comum, mas eu diria que esse é exatamente o tipo de contrato que a API do Android deve oferecer, além de oferecer muito mais flexibilidade ao sistema Android, minimizando a vida útil dos aplicativos associados. dados. 2) A classe Application fornece ao desenvolvedor do aplicativo um único detentor de instância para state, que é muito diferente de um detentor de Estado Singleton. Para obter uma lista das diferenças, consulte o link de explicação Singleton acima.
Dianne continua: "... provavelmente será algo de que você se arrependerá no futuro, ao encontrar o objeto Application se tornando uma grande bagunça do que deveria ser uma lógica de aplicativo independente". Certamente isso não está incorreto, mas esse não é um motivo para escolher o Singleton sobre a subclasse Aplicativo. Nenhum dos argumentos de Diane fornece uma razão para que o uso de um Singleton seja melhor que uma subclasse Application, tudo o que ela tenta estabelecer é que o uso de um Singleton não é pior que uma subclasse Application, que acredito ser falsa.
Ela continua: "E isso leva mais naturalmente a como você deve gerenciar essas coisas - inicializando-as sob demanda". Isso ignora o fato de que não há motivo para que você não possa inicializar sob demanda usando também uma subclasse Application. Novamente, não há diferença.
Dianne termina com "A própria estrutura possui toneladas e toneladas de singletons para todos os poucos dados compartilhados que mantém para o aplicativo, como caches de recursos carregados, conjuntos de objetos etc. Ele funciona muito bem". Não estou argumentando que o uso de Singletons não funcione bem ou não seja uma alternativa legítima. Estou argumentando que os Singletons não fornecem um contrato tão forte com o sistema Android quanto o uso de uma subclasse Application, e além disso, o uso de Singletons geralmente aponta para um design inflexível, que não é facilmente modificado e leva a muitos problemas no caminho. IMHO, o forte contrato que a API Android oferece aos aplicativos de desenvolvedor é um dos aspectos mais atraentes e agradáveis da programação com o Android, e ajudou a levar à adoção antecipada do desenvolvedor, o que levou a plataforma Android ao sucesso que ela tem hoje.
Dianne também comentou abaixo, mencionando uma desvantagem adicional no uso de subclasses de Aplicativo, eles podem incentivar ou facilitar a gravação de menos código de desempenho. Isso é muito verdadeiro e editei esta resposta para enfatizar a importância de considerar o perf aqui e adotar a abordagem correta se você estiver usando a subclassificação de aplicativos. Como Dianne afirma, é importante lembrar que sua classe Application será instanciada toda vez que seu processo for carregado (pode ser várias vezes ao mesmo tempo se seu aplicativo for executado em vários processos!), Mesmo que o processo esteja sendo carregado apenas para uma transmissão em segundo plano evento. Portanto, é importante usar a classe Application mais como um repositório para ponteiros para componentes compartilhados do seu aplicativo, e não como um local para qualquer processamento!
Deixo você com a seguinte lista de desvantagens para Singletons, roubadas do link anterior do StackExchange:
- Incapacidade de usar classes abstratas ou de interface;
- Incapacidade de subclasse;
- Alto acoplamento em todo o aplicativo (difícil de modificar);
- Difícil de testar (não pode falsificar / zombar em testes de unidade);
- Difícil de paralelizar no caso de estado mutável (requer travamento extenso);
e adicione o meu:
- Contrato vitalício incerto e incontrolável, inadequado para o desenvolvimento do Android (ou da maioria dos outros);