Usando a classe Android Application para persistir os dados

112

Estou trabalhando em um aplicativo Android bastante complexo que requer uma grande quantidade de dados sobre o aplicativo (eu diria um total de cerca de 500 KB - isso é grande para um dispositivo móvel?). Pelo que posso dizer, qualquer mudança de orientação na aplicação (na atividade, para ser mais preciso) provoca uma destruição e recriação completa da atividade. Com base em minhas descobertas, a classe Application não tem o mesmo ciclo de vida (ou seja, é, para todos os efeitos, sempre instanciada). Faz sentido armazenar as informações de estado dentro da classe do aplicativo e, em seguida, referenciá-las a partir da Activity ou esse geralmente não é o método "aceitável" devido a restrições de memória em dispositivos móveis? Eu realmente aprecio qualquer conselho sobre este assunto. Obrigado!

Dave
fonte
8
Apenas tenha em mente que os dados em seu aplicativo ainda podem ser excluídos se seu aplicativo ficar em segundo plano, portanto, esta não é uma solução para dados persistentes que você sempre deseja recuperar. Ele serve apenas como um método para não ter que recriar objetos caros com tanta frequência.
Cheryl Simon
2
Mayra; Não acho que o aplicativo seja "normalmente" excluído (embora, como alguém apontou mais tarde neste tópico, "possa" ser). Provavelmente irei usar algum tipo de abordagem "híbrida" de usar o aplicativo para armazenar e carregar os dados, mas depois usar o atributo "android :idance" na atividade no arquivo de manifesto para substituir o comportamento normal de demolindo e reconstruindo a atividade. Tudo isso, é claro, pressupõe que o aplicativo pode determinar "quando" ele está sendo destruído para que os dados possam ser persistidos.
Dave de

Respostas:

134

Eu não acho que 500kb será um grande negócio.

O que você descreveu é exatamente como resolvi meu problema de perda de dados em uma atividade. Criei um singleton global na classe Application e pude acessá-lo a partir das atividades que usei.

Você pode passar dados em um Global Singleton se ele for muito usado.

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

Em seguida, chame-o em qualquer atividade:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

Eu discuto isso aqui em minha postagem do blog , na seção "Singleton Global".

Bryan Denny
fonte
1
Infelizmente, a postagem do blog em questão não está mais disponível nesse endereço.
mikebabcock
1
Tenho mudado algumas coisas no meu site. Até que seja corrigido, você pode encontrá-lo em archive.org aqui: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Bryan Denny
1
Sei que este é um post antigo, mas acabei de encontrar um problema que pode ser resolvido, porém essa classe precisa ser declarada no manifesto de alguma forma, não? Eu não posso acessar a aula, então sinto que isso é o que estou perdendo ...
Ziv Kesten
1
@ZivKesten Que tal adicionar o atributo name = à tag do aplicativo dentro do manifesto?
MikeC
@mgc, obrigado, já faz um tempo, e sim, foi assim que resolvi, também criei instâncias dessa classe sempre que necessário, dando a ela getApplicationContext () com um elenco para esta classe
Ziv Kesten
57

Aqueles que contam com Applicationinstância estão errados. À primeira vista, pode parecer que Applicationexiste enquanto todo o processo do aplicativo existir, mas essa é uma suposição incorreta.

O sistema operacional pode matar processos conforme necessário. Todos os processos são divididos em 5 níveis de "capacidade de eliminação" especificados no documento .

Portanto, por exemplo, se seu aplicativo ficar em segundo plano devido ao usuário responder a uma chamada, dependendo do estado da RAM, o sistema operacional pode (ou não) interromper seu processo (destruindo a Applicationinstância no processo) .

Acho que uma abordagem melhor seria manter seus dados no arquivo de armazenamento interno e depois lê-los quando a atividade for retomada.

ATUALIZAR:

Recebi muitos feedbacks negativos, então é hora de acrescentar um esclarecimento. :) Bem, inicialmente eu realmente usei uma suposição errada de que o estado é realmente importante para o aplicativo. No entanto, se o seu aplicativo estiver certo que às vezes o estado é perdido (podem ser algumas imagens que serão apenas relidas / baixadas novamente), então está totalmente OK mantê-lo como membro Application.

Vit Khudenko
fonte
14
Se o aplicativo for encerrado, quem se importa, certo? O aplicativo acabou. Pelo que entendi, o Android recuperará processos que contêm memória como atividades. Se o processo que contém o aplicativo for encerrado (se o Android fará isso?), É essencialmente como encerrar o aplicativo. O usuário precisará iniciar o aplicativo novamente e, nesse ponto, quem se importa? É uma nova instância do aplicativo.
Andrew
14
Esta foi uma surpresa desagradável para nós na produção. Acredite em mim, o Android mata processos, depende apenas do estado da RAM e de outros fatores descritos na documentação. Foi um pesadelo para nós, então eu apenas compartilho minha experiência real. Bem, não tínhamos isso em emuladores, mas no mundo real alguns dispositivos estão 'sobrecarregados' com aplicativos, então interromper um processo em segundo plano é uma situação normal. Sim, se o usuário decidir colocar o aplicativo em primeiro plano - o sistema operacional restaura sua pilha incluindo a Applicationinstância, no entanto, não haverá seus dados estáticos com os quais você conta, a menos que você os persista.
Vit Khudenko em
2
Acho que provavelmente vou usar uma abordagem híbrida. Eu já conhecia o truque do manifesto para anular a mudança de orientação (que tem outros benefícios). Como o aplicativo é um jogo, não tenho certeza se persistir os dados entre as inicializações é "importante" o suficiente; embora provavelmente não seja terrivelmente difícil, já que a maioria dos dados pode ser serializada (embora eu não queira serializar e desserializar entre cada mudança de orientação). Eu definitivamente aprecio a contribuição. Eu não diria que aqueles que dependem da instância do App estão "errados". Depende muito do app :).
Dave
1
@Arhimed, você está generalizando demais sua resposta. E sugerindo uma abordagem restrita com base em sua suposição. Hipótese falsa: os dados mantidos nas variáveis ​​estáticas precisam ser persistentes nas sessões do aplicativo. Pode haver vários casos de uso em que os dados são triviais e não precisam ser persistidos imediatamente.
Mandar Limaye
2
Tenho cerca de 1mb de dados com estrutura complicada. Serializar / desserializar pode me custar até 2-3 segundos quando o dispositivo está sobrecarregado de trabalho. A ideia de economizar / carregar entre as atividades custa muito tempo. Eu uso o aplicativo como armazenamento. É claro que minha classe de dados armazenada na instância do aplicativo verificou todos os métodos - os dados ainda estão vivos ou precisam ser carregados. Portanto, Dave deve: 1. fornecer funções de carregamento / salvar 2. manter os dados no aplicativo. 3. Lógica de verificação tripla para acesso aos dados.
Kostadin
6

Se você deseja acessar o "Global Singleton" fora de uma atividade e não deseja passar no Context por todos os objetos envolvidos para obter o singleton, você pode apenas definir um atributo estático em sua classe de aplicativo, que contém a referência para em si. Basta inicializar o atributo no onCreate()método.

Por exemplo:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

Como as subclasses de Applicationtambém podem obter os Recursos, você pode acessá-los simplesmente ao definir um método estático, que os retorna, como:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

Mas tenha muito cuidado ao passar referências de contexto para evitar vazamentos de memória .

saxos
fonte
6
Você se esqueceu de observar que deve adicionar o atributo xml android: name = ". ApplicationController" a tag do aplicativo em seu manifesto para que a classe seja instanciada.
eggie5
Na verdade, você não precisa estender Applicationpara fazer isso. Você pode declarar uma variável de membro estático em qualquer classe para fazer isso.
David Wasser
2

Dave, que tipo de dados são? Se forem dados gerais que pertencem ao aplicativo como um todo (exemplo: dados do usuário), estenda a classe Application e armazene-a lá. Se os dados pertencerem à Activity, você deve usar os manipuladores onSaveInstanceState e onRestoreInstanceState para persistir os dados na rotação da tela.

Andrew
fonte
E se os dados forem realmente grandes para armazenar em um pacote? Isto é o que estou recebendo: android.os.TransactionTooLargeException: tamanho da parcela de dados 838396 bytes
Arjun Issar
1

Na verdade, você pode substituir a funcionalidade de orientação para garantir que sua atividade não seja destruída e recriada. Olhe aqui .

Grantland Chew
fonte
16
Você pode fazer muitas coisas. Isso não significa que sejam boas ideias. Isso não é uma boa ideia.
Andrew
Testar alterando a orientação da tela é a maneira mais fácil de garantir que seu aplicativo faça o que o Android supõe que ele faça.
18446744073709551615
0

Você pode criar uma classe de aplicativo e salvar todos os seus dados nesse calss para usar em qualquer lugar em seu aplicativo.

Ashish Jaiswal
fonte
0

Eu sei que esta é uma questão muito antiga, mas usar o ViewModel dos componentes do jetpack é a melhor maneira de preservar os dados entre a rotação de atividades.

A classe ViewModel foi projetada para armazenar e gerenciar dados relacionados à IU de uma maneira consciente do ciclo de vida. A classe ViewModel permite que os dados sobrevivam às mudanças de configuração, como rotações de tela.

Dharmendra
fonte