Estou criando um aplicativo que requer login. Eu criei a principal e a atividade de login.
No principal onCreate
método de atividade , adicionei a seguinte condição:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
loadSettings();
if(strSessionString == null)
{
login();
}
...
}
O onActivityResult
método que é executado quando o formulário de login é finalizado se parece com o seguinte:
@Override
public void onActivityResult(int requestCode,
int resultCode,
Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode)
{
case(SHOW_SUBACTICITY_LOGIN):
{
if(resultCode == Activity.RESULT_OK)
{
strSessionString = data.getStringExtra(Login.SESSIONSTRING);
connectionAvailable = true;
strUsername = data.getStringExtra(Login.USERNAME);
}
}
}
O problema é que o formulário de login às vezes aparece duas vezes (o login()
método é chamado duas vezes) e também quando o teclado do telefone desliza, o formulário de login aparece novamente e acho que o problema é a variável strSessionString
.
Alguém sabe como definir a variável global para evitar que o formulário de login apareça após o usuário já se autenticar com êxito?
android
singleton
global-variables
state
Niko Gamulin
fonte
fonte
Respostas:
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 qualquerContext.getApplicationContext()
método (Activity
também fornece um métodogetApplication()
que tem exatamente o mesmo efeito). A seguir, é apresentado um exemplo extremamente simplificado, com ressalvas a seguir: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:
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:
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:
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:
e adicione o meu:
fonte
Crie esta subclasse
No AndroidManifest.xml, adicione android: name
Exemplo
fonte
java.lang.IllegalAccessException: access to class is not allowed
A maneira sugerida por Soonil de manter um estado para o aplicativo é boa, porém tem um ponto fraco - há casos em que o SO mata todo o processo do aplicativo. Aqui está a documentação sobre isso - Processos e ciclos de vida .
Considere um caso: seu aplicativo entra em segundo plano porque alguém está ligando para você (o aplicativo Phone está em primeiro plano agora). Nesse caso, && sob algumas outras condições (verifique o link acima para saber o que poderiam ser), o sistema operacional pode interromper o processo de inscrição, incluindo a
Application
instância da subclasse. Como resultado, o estado está perdido. Quando você retornar posteriormente ao aplicativo, o sistema operacional restaurará sua pilha de atividades e aApplication
instância da subclasse, independentemente domyState
camponull
.No AFAIK, a única maneira de garantir a segurança do estado é usar qualquer tipo de persistência do estado, por exemplo, usar um privado para o arquivo do aplicativo ou
SharedPrefernces
(eventualmente ele usa um privado para o arquivo do aplicativo no sistema de arquivos interno).fonte
SharedPreferences
; é assim que eu tenho visto isso. Acho estranho abusar do sistema de preferências para o estado salvo, mas funciona tão bem que o problema se torna apenas uma questão de terminologia.Apenas uma nota ..
adicionar:
ou o que você nomeou sua subclasse para a tag existente
<application>
. Continuei tentando adicionar outra<application>
tag ao manifesto e receberia uma exceção.fonte
Também não consegui encontrar como especificar a tag do aplicativo, mas depois de pesquisar bastante no Google, ficou óbvio a partir dos documentos do arquivo de manifesto: use android: name, além do ícone e do rótulo padrão na sub-rotina do aplicativo.
android: name O nome completo de uma subclasse Aplicativo implementada para o aplicativo. Quando o processo do aplicativo é iniciado, essa classe é instanciada antes de qualquer um dos componentes do aplicativo.
A subclasse é opcional; a maioria dos aplicativos não precisará de um. Na ausência de uma subclasse, o Android usa uma instância da classe Application básica.
fonte
Que tal garantir a coleta de memória nativa com essas estruturas globais?
As atividades têm um
onPause/onDestroy()
método chamado destruição, mas a classe Application não possui equivalentes. Que mecanismo é recomendado para garantir que as estruturas globais (especialmente aquelas que contêm referências à memória nativa) sejam coletadas de maneira apropriada quando o aplicativo é morto ou a pilha de tarefas é colocada em segundo plano?fonte
Você só precisa definir um nome de aplicativo como abaixo, que funcionará:
fonte
Como foi discutido acima, o SO pode matar o APPLICATION sem nenhuma notificação (não há evento onDestroy), portanto não há como salvar essas variáveis globais.
SharedPreferences poderia ser uma solução, EXCETO você tem variáveis COMPLEX STRUCTURED (no meu caso, eu tinha um array inteiro para armazenar os IDs que o usuário já manipulou). O problema com as SharedPreferences é que é difícil armazenar e recuperar essas estruturas sempre que os valores forem necessários.
No meu caso, eu tinha um SERVICE em segundo plano para poder mover essas variáveis para lá e, como o serviço tem um evento onDestroy, eu poderia salvar esses valores facilmente.
fonte
Se algumas variáveis estiverem armazenadas no sqlite e você deve usá-las na maioria das atividades em seu aplicativo. então Application talvez seja a melhor maneira de alcançá-lo. Consultar as variáveis do banco de dados quando o aplicativo foi iniciado e armazená-las em um campo. Então você pode usar essas variáveis em suas atividades.
Portanto, encontre o caminho certo e não há melhor caminho.
fonte
Você pode ter um campo estático para armazenar esse tipo de estado. Ou coloque-o no recurso Bundle e restaure a partir daí em onCreate (Bundle savedInstanceState). Apenas certifique-se de entender completamente o ciclo de vida gerenciado do aplicativo Android (por exemplo, por que o login () é chamado na alteração da orientação do teclado).
fonte
NÃO use outra
<application>
tag no arquivo de manifesto. Basta fazer uma alteração na<application>
tag existente ; adicione esta linhaandroid:name=".ApplicationName"
emApplicationName
que será o nome da sua subclasse (use para armazenar global) que você está prestes a criar.então, finalmente, sua tag ONE AND ONLY
<application>
no arquivo de manifesto deve ficar assim: -fonte
você pode usar as intenções, o sqlite ou as preferências compartilhadas. Quando se trata do armazenamento de mídia, como documentos, fotos e vídeos, você pode criar os novos arquivos.
fonte
Você pode fazer isso usando duas abordagens:
Usando preferências compartilhadas
Usando a classe Application
Exemplo:
Você pode usar a classe acima para implementar o logon em sua MainActivity como abaixo. O código será mais ou menos assim:
Este método funcionará para armazenamento temporário. Você realmente não tem idéia de quando o sistema operacional vai matar o aplicativo, por causa da pouca memória. Quando seu aplicativo está em segundo plano e o usuário está navegando em outro aplicativo que exige mais memória para ser executado, seu aplicativo será eliminado, pois o sistema operacional deu mais prioridade aos processos em primeiro plano do que em segundo plano. Portanto, seu objeto de aplicativo será nulo antes que o usuário efetue logout. Por isso, recomendo usar o segundo método especificado acima.
Usando preferências compartilhadas.
fonte
Na atividade, o resultado é chamado antes no resumo. Portanto, mova sua verificação de login para continuar e seu segundo login poderá ser bloqueado quando a atividade secomd retornar um resultado positivo. No currículo é chamado toda vez, então não há preocupações de não ser chamado pela primeira vez.
fonte
A abordagem da subclasse também foi usada pela estrutura BARACUS. Do meu ponto de vista, a subclasse de aplicativos destinava-se a trabalhar com os ciclos de vida do Android; é isso que qualquer contêiner de aplicativos faz. Em vez de ter globais, registro os beans nesse contexto e os deixo sendo injetados em qualquer classe gerenciável pelo contexto. Toda instância de bean injetado é realmente um singleton.
Veja este exemplo para detalhes
Por que o trabalho manual se você pode ter muito mais?
fonte
fonte
Você pode criar uma classe que estenda a
Application
classe e, em seguida, declarar sua variável como um campo dessa classe e fornecer o método getter para ela.E então, para acessar essa variável em sua Atividade, use o seguinte:
fonte