Nos relatórios de erro do console do desenvolvedor, às vezes vejo relatórios com problemas de NPE. Não entendo o que há de errado com meu código. No emulador e meu aplicativo de dispositivo funciona bem sem execuções hipotecárias, no entanto, alguns usuários obtêm NullPointerException na classe de fragmento quando o método getActivity () é chamado.
Atividade
pulic class MyActivity extends FragmentActivity{
private ViewPager pager;
private TitlePageIndicator indicator;
private TabsAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
pager = (ViewPager) findViewById(R.id.pager);
indicator = (TitlePageIndicator) findViewById(R.id.indicator);
adapter = new TabsAdapter(getSupportFragmentManager(), false);
adapter.addFragment(new FirstFragment());
adapter.addFragment(new SecondFragment());
indicator.notifyDataSetChanged();
adapter.notifyDataSetChanged();
// push first task
FirstTask firstTask = new FirstTask(MyActivity.this);
// set first fragment as listener
firstTask.setTaskListener((TaskListener) adapter.getItem(0));
firstTask.execute();
}
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Fragment currentFragment = adapter.getItem(position);
((Taskable) currentFragment).executeTask();
}
@Override
public void onPageScrolled(int i, float v, int i1) {}
@Override
public void onPageScrollStateChanged(int i) {}
});
}
Classe AsyncTask
public class FirstTask extends AsyncTask{
private TaskListener taskListener;
...
@Override
protected void onPostExecute(T result) {
...
taskListener.onTaskComplete(result);
}
}
Classe de fragmento
public class FirstFragment extends Fragment immplements Taskable, TaskListener{
public FirstFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_view, container, false);
}
@Override
public void executeTask() {
FirstTask firstTask = new FirstTask(MyActivity.this);
firstTask.setTaskListener(this);
firstTask.execute();
}
@Override
public void onTaskComplete(T result) {
// NPE is here
Resources res = getActivity().getResources();
...
}
}
Talvez esse erro ocorra quando os aplicativos forem retomados em segundo plano. Nesse caso, como devo lidar com essa situação corretamente?
android
android-fragments
android-activity
android-asynctask
nullpointerexception
Georgy Gobozov
fonte
fonte
Respostas:
Parece que encontrei uma solução para o meu problema. Muito boas explicações são dadas aqui e aqui . Aqui está o meu exemplo:
A idéia principal desse código é que, enquanto você executa o aplicativo normalmente, você cria novos fragmentos e os passa para o adaptador. Quando você está reiniciando, o gerenciador de fragmentos de aplicativos já possui a instância desse fragmento e é necessário obtê-lo do gerenciador de fragmentos e transmiti-lo ao adaptador.
ATUALIZAR
Além disso, é uma boa prática ao usar fragmentos para verificar isAdded antes de getActivity () ser chamado. Isso ajuda a evitar uma exceção de ponteiro nulo quando o fragmento é desanexado da atividade. Por exemplo, uma atividade pode conter um fragmento que envia uma tarefa assíncrona. Quando a tarefa é concluída, o ouvinte onTaskComplete é chamado.
Se abrirmos o fragmento, pressionar uma tarefa e pressionar rapidamente para retornar à atividade anterior, quando a tarefa for concluída, ela tentará acessar a atividade em onPostExecute () chamando o método getActivity (). Se a atividade já estiver desanexada e esta verificação não estiver lá:
então o aplicativo trava.
fonte
isAdded()
antes de cada acesso ... torna o código feio.if(isAdded())
ouif(getActivity() != null)
Ok, eu sei que esta questão está realmente resolvida, mas decidi compartilhar minha solução para isso. Eu criei a classe pai abstrata para o meu
Fragment
:Como você pode ver, adicionei um ouvinte. Sempre que precisar, em
Fragments
Activity
vez do padrãogetActivity()
, preciso ligarfonte
O melhor para se livrar disso é manter a referência da atividade quando
onAttach
for chamada e usar a referência da atividade sempre que necessário, por exemploEditado, pois
onAttach(Activity)
está depreciado e agoraonAttach(Context)
está sendo usadofonte
getActivity()
retornar nulo, é porque você não está mais em uma atividade. Esta é uma solução alternativa suja.Não chame métodos dentro do Fragmento que exijam getActivity () até onStart na Atividade pai.
fonte
eu estive lutando contra esse tipo de problema há um tempo e acho que encontrei uma solução confiável.
É muito difícil ter certeza de que isso
this.getActivity()
não retornaránull
para umFragment
, especialmente se você estiver lidando com algum tipo de comportamento de rede que dê tempo suficiente ao seu código para se retirarActivity
referências.Na solução abaixo, declaro uma pequena classe de gerenciamento chamada
ActivityBuffer
. Essencialmente, issoclass
lida com a manutenção de uma referência confiável a uma propriedadeActivity
e com a promessa de executarRunnable
s dentro de umActivity
contexto válido sempre que houver uma referência válida disponível. ElesRunnable
estão agendados para execução no thread da interface do usuário imediatamente, seContext
disponível, caso contrário, a execução será adiada até queContext
esteja pronto.Em termos de sua implementação, devemos ter o cuidado de aplicar os métodos do ciclo de vida para coincidir com o comportamento descrito acima por Pawan M :
Finalmente, em todas as áreas dentro da sua
Fragment
extensãoBaseFragment
que você não é confiável em relação a uma ligaçãogetActivity()
, basta ligarthis.getActivityBuffer().safely(...)
e declarar umaActivityBuffer.IRunnable
para a tarefa!O conteúdo do seu
void run(final Activity pActivity)
é garantido para executar ao longo do thread da interface do usuário.O
ActivityBuffer
pode então ser usado da seguinte maneira:fonte
fonte
Sei que essa é uma pergunta antiga, mas acho que devo fornecer minha resposta, porque meu problema não foi resolvido por outras pessoas.
primeiro de tudo: eu estava adicionando fragmentos dinamicamente usando fragmentTransactions. Segundo: meus fragmentos foram modificados usando AsyncTasks (consultas de banco de dados em um servidor). Terceiro: meu fragmento não foi instanciado no início da atividade. Quarto: usei uma instanciação personalizada de fragmento "crie ou carregue" para obter a variável de fragmento. Quarto: a atividade foi recriada por causa da mudança de orientação
O problema era que eu queria "remover" o fragmento por causa da resposta da consulta, mas o fragmento foi criado incorretamente pouco antes. Não sei por que, provavelmente por causa do "commit" ser feito posteriormente, o fragmento ainda não foi adicionado na hora de removê-lo. Portanto, getActivity () estava retornando nulo.
Solução: 1) Eu tive que verificar se estava tentando encontrar corretamente a primeira instância do fragmento antes de criar uma nova. 2) Eu tive que colocar serRetainInstance (true) nesse fragmento para mantê-lo na mudança de orientação (sem backstack). necessário, portanto, não há problema) 3) Em vez de "recriar ou obter fragmento antigo" imediatamente antes de "removê-lo", coloquei o fragmento diretamente no início da atividade. Instanciando-o no início da atividade, em vez de "carregar" (ou instanciar) a variável de fragmento antes de removê-lo, evitou problemas de getActivity.
fonte
No Kotlin, você pode tentar desta maneira lidar com a condição nula getActivity ().
Ele verificará se a atividade é nula ou não e, se não for nula, execute o código interno.
fonte