Baixo alguns dados da Internet no thread de segundo plano (eu uso AsyncTask
) e exibo uma caixa de diálogo de progresso durante o download. A orientação muda, a Atividade é reiniciada e, em seguida, minha AsyncTask é concluída - desejo encerrar a caixa de diálogo de progresso e iniciar uma nova Atividade. Mas, por vezes, chamar a opção unlockDialog gera uma exceção (provavelmente porque a Atividade foi destruída e a nova Atividade ainda não foi iniciada).
Qual é a melhor maneira de lidar com esse tipo de problema (atualizar a interface do usuário a partir do encadeamento em segundo plano que funciona mesmo que o usuário altere a orientação)? Alguém do Google forneceu alguma "solução oficial"?
Respostas:
Etapa 1: crie
AsyncTask
umastatic
classe aninhada ou uma classe totalmente separada, mas não uma classe interna (aninhada não estática).Etapa 2:
AsyncTask
Segure oActivity
através de um membro de dados, definido através do construtor e de um configurador.Etapa 3: Ao criar o
AsyncTask
, forneça a correnteActivity
ao construtor.Etapa 4:
onRetainNonConfigurationInstance()
retorne aAsyncTask
, depois de desconectá-la da atividade original que está indo embora agora.Etapa 5: no
onCreate()
casogetLastNonConfigurationInstance()
contrárionull
, transmita-o à suaAsyncTask
turma e ligue para o levantador para associar sua nova atividade à tarefa.Etapa 6: Não consulte o membro de dados da atividade de
doInBackground()
.Se você seguir a receita acima, tudo funcionará.
onProgressUpdate()
eonPostExecute()
são suspensos entre o inícioonRetainNonConfigurationInstance()
e o final do subsequenteonCreate()
.Aqui está um projeto de amostra demonstrando a técnica.
Outra abordagem é abandonar o
AsyncTask
e mover seu trabalho para umIntentService
. Isso é particularmente útil se o trabalho a ser feito puder ser longo e continuar independentemente do que o usuário faz em termos de atividades (por exemplo, baixar um arquivo grande). Você pode usar uma transmissão ordenadaIntent
para que a atividade responda ao trabalho que está sendo realizado (se ainda estiver em primeiro plano) ou aumente aNotification
para informar ao usuário se o trabalho foi realizado. Aqui está uma postagem de blog com mais informações sobre esse padrão.fonte
onRetainNonConfigurationInstance()
foi descontinuado e a alternativa sugerida é usarsetRetainInstance()
, mas não retorna um objeto. É possível lidarasyncTask
com mudanças na configuraçãosetRetainInstance()
?Fragment
porãoAsyncTask
. Tenha oFragment
chamadosetRetainInstance(true)
em si. Tenha aAsyncTask
única conversa com oFragment
. Agora, em uma alteração na configuração, oFragment
item não é destruído e recriado (mesmo que a atividade seja) e, portanto,AsyncTask
é retido na alteração da configuração.A resposta aceita foi muito útil, mas não possui uma caixa de diálogo de progresso.
Felizmente para você, leitor, criei um exemplo extremamente abrangente e funcional de um AsyncTask com uma caixa de diálogo de progresso !
fonte
Trabalhei por uma semana para encontrar uma solução para esse dilema sem recorrer à edição do arquivo de manifesto. As suposições para esta solução são:
Implementação
Você precisará copiar os dois arquivos encontrados na parte inferior desta postagem no seu espaço de trabalho. Apenas certifique-se de que:
Todos os seus
Activity
s devem se estenderBaseActivity
Em
onCreate()
,super.onCreate()
deve ser chamado depois que você inicializar qualquer membro que precise ser acessado por seusASyncTask
s. Substitua tambémgetContentViewId()
para fornecer o ID do layout do formulário.Substitua
onCreateDialog()
como de costume para criar caixas de diálogo gerenciadas pela atividade.Veja o código abaixo para obter uma amostra de classe interna estática para criar suas AsyncTasks. Você pode armazenar seu resultado no mResult para acessar mais tarde.
E, finalmente, para iniciar sua nova tarefa:
É isso aí! Espero que esta solução robusta ajude alguém.
BaseActivity.java (organize você mesmo as importações)
SuperAsyncTask.java
fonte
Sim.
A solução é mais uma proposta de arquitetura de aplicativo do que apenas algum código .
Eles propuseram 3 padrões de design que permitem que um aplicativo funcione em sincronia com um servidor, independentemente do estado do aplicativo (ele funcionará mesmo que o usuário termine o aplicativo, o usuário altere a tela, o aplicativo seja encerrado, todos os outros estados possíveis em que uma operação de dados em segundo plano pode ser interrompida, isso abrange)
A proposta é explicada no discurso sobre aplicativos clientes REST Android durante o Google I / O 2010 por Virgil Dobjanschi. Tem uma hora de duração, mas vale a pena assistir.
A base é abstrair as operações de rede para uma
Service
que funcione independentemente de qualquerActivity
aplicação. Se você estiver trabalhando com bancos de dados, useContentResolver
eCursor
daria a você um padrão Observador pronto para uso que é conveniente para atualizar a interface do usuário sem lógica adicional, depois que você atualiza seu banco de dados local com os dados remotos buscados. Qualquer outro código pós-operação seria executado por meio de um retorno de chamada passado para oService
(eu uso umaResultReceiver
subclasse para isso).De qualquer forma, minha explicação é bastante vaga, você definitivamente deve assistir ao discurso.
fonte
Embora a resposta de Mark (CommonsWare) realmente funcione para alterações de orientação, ela falha se a Atividade for destruída diretamente (como no caso de uma ligação telefônica).
Você pode lidar com as alterações de orientação E os raros eventos de Atividade destruídos usando um objeto Aplicativo para referenciar sua ASyncTask.
Há uma excelente explicação do problema e da solução aqui :
Crédito é totalmente para Ryan por descobrir isso.
fonte
Após 4 anos, o Google resolveu o problema chamando setRetainInstance (true) em Activity onCreate. Ele preservará sua instância de atividade durante a rotação do dispositivo. Eu também tenho uma solução simples para Android mais antigo.
fonte
você deve chamar todas as ações de atividade usando o manipulador de atividades. Portanto, se você estiver em algum segmento, crie um Runnable e publique usando o Manipulador da Activitie. Caso contrário, seu aplicativo falhará às vezes, com exceção fatal.
fonte
Esta é a minha solução: https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog
Basicamente, as etapas são:
onSaveInstanceState
para salvar a tarefa se ela ainda estiver em processamento.onCreate
eu recebo a tarefa se ela foi salva.onPause
descartar oProgressDialog
se é mostrado.onResume
eu mostroProgressDialog
se a tarefa ainda está sendo processada.fonte