java.lang.IllegalStateException: fragmento não anexado à atividade

148

Eu raramente recebo esse erro ao fazer uma chamada de API.

java.lang.IllegalStateException: Fragment  not attached to Activity

Eu tentei colocar o código dentro do isAdded()método para verificar se o fragmento está atualmente adicionado à sua atividade, mas ainda assim raramente recebo esse erro. Não consigo entender por que ainda estou recebendo esse erro. Como posso evitar isso?

Está mostrando erro na linha

cameraInfo.setId(getResources().getString(R.string.camera_id));

Abaixo está o exemplo de chamada da API que estou fazendo.

SAPI.getInfo(getActivity(),
                new APIResponseListener() {
                    @Override
                    public void onResponse(Object response) {


                        cameraInfo = new SInfo();
                        if(isAdded()) {
                            cameraInfo.setId(getResources().getString(R.string.camera_id));
                            cameraInfo.setName(getResources().getString(R.string.camera_name));
                            cameraInfo.setColor(getResources().getString(R.string.camera_color));
                            cameraInfo.setEnabled(true);
                        }


                    }

                    @Override
                    public void onError(VolleyError error) {
                        mProgressDialog.setVisibility(View.GONE);
                        if (error instanceof NoConnectionError) {
                            String errormsg = getResources().getString(R.string.no_internet_error_msg);
                            Toast.makeText(getActivity(), errormsg, Toast.LENGTH_LONG).show();
                        }
                    }
                });
Desenvolvedor Android
fonte
Para obter mais informações, consulte o site da câmera.Instalar a câmera.
Ashwin H

Respostas:

203

Este erro ocorre devido ao efeito combinado de dois fatores:

  • A solicitação HTTP, quando concluída, chama um onResponse()ou onError()(que funciona no encadeamento principal) sem saber se o Activityainda está em primeiro plano ou não. Se ele Activityse foi (o usuário navegou em outro lugar), getActivity()retorna nulo.
  • O Volley Responseé expresso como uma classe interna anônima, que possui implicitamente uma forte referência à Activityclasse externa . Isso resulta em um vazamento de memória clássico.

Para resolver esse problema, você deve sempre fazer:

Activity activity = getActivity();
if(activity != null){

    // etc ...

}

e também, use isAdded()noonError() método também:

@Override
public void onError(VolleyError error) {

    Activity activity = getActivity(); 
    if(activity != null && isAdded())
        mProgressDialog.setVisibility(View.GONE);
        if (error instanceof NoConnectionError) {
           String errormsg = getResources().getString(R.string.no_internet_error_msg);
           Toast.makeText(activity, errormsg, Toast.LENGTH_LONG).show();
        }
    }
}
YS
fonte
2
Ao usar solicitações Volley AsyncTaskes dentro de um Activity, não há maneira infalível de evitar NPEs '. Sempre existe a chance de o usuário navegar para longe da corrente Activityenquanto um dos threads faz algo em segundo plano e, quando o thread é concluído e onPostExecute()ou onResponse()é chamado, não há Activity. Tudo o que você pode fazer é fazer verificações de referências nulas em vários pontos no seu código, e que não é à prova de balas :)
YS
2
O teste do macaco para Android (macaco de shell adb) é realmente bom para erradicar esse erro, se você ainda não o explicou de maneira genérica / global.
precisa saber é o seguinte
5
o isAdded () é suficiente, o booleano público final isAdded () {retorna mActivity! = null && mAdded; }
lannyf
2
@ruselli: Verifica o addedsinalizador booleano e se a Activityinstância atual é nullou não.
YS
1
@gauravjain Evite fazer solicitações assíncronas (como chamadas HTTP) diretamente do Fragments. Faça isso a partir da atividade e deve ficar bem. Além disso, referências claras ao Fragment do FragmentManager, é uma boa prática e é a melhor maneira de evitar vazamentos de memória.
YS
56

O ciclo de vida do fragmento é muito complexo e cheio de erros, tente adicionar:

Activity activity = getActivity(); 
if (isAdded() && activity != null) {
...
}
Miroslav Michalec
fonte
2
Onde eu deveria colocá-lo?
Vaclovas Rekašius Jr.
1
@ VaclovasRekašiusJr. Parece praticamente em qualquer lugar em que você deseja acessar a Atividade de dentro do fragmento. Diversão!
precisa saber é o seguinte
2
o que devo fazer se a atividade == nula. para manter vivo o meu pedido @Miroslav
pavel
Olhe para o isAdded (), que você pode encontrados "! = Null actividade" não é redundante
BertKing
@BertKing return mHost != null && mAdded;- Isso é o que dentro do método fragment.isAdded (). Eu pensei que mHost é uma atividade se você rastrear, mas parece que mHost está dentro de FragmentActivity. Então, provavelmente, você está certo. Alguma adição?
Johnny Five
14

Encontrei Solução muito simples O método isAdded () , que é um dos métodos de fragmento para identificar se esse fragmento atual está anexado à sua atividade ou não.

podemos usar isso como em qualquer lugar na classe de fragmentos, como:

if(isAdded())
{

// using this method, we can do whatever we want which will prevent   **java.lang.IllegalStateException: Fragment not attached to Activity** exception.

}
Dharmesh Baldha
fonte
12

Exceção: java.lang.IllegalStateException: Fragment

DeadlineListFragment {ad2ef970} não anexado à Atividade

Categoria: Ciclo de vida

Descrição : ao executar uma operação demorada no encadeamento em segundo plano (por exemplo, AsyncTask), um novo fragmento foi criado nesse meio tempo e foi desanexado para a Atividade antes da conclusão do encadeamento em segundo plano. O código no thread da interface do usuário (por exemplo, onPostExecute) chama um fragmento desanexado, lançando essa exceção.

Solução de correção:

  1. Cancele o encadeamento em segundo plano ao pausar ou parar o fragmento

  2. Use isAdded () para verificar se o fragmento está anexado e, em seguida, para getResources () da atividade.

Rahil Ali
fonte
11

posso estar atrasado, mas posso ajudar alguém ... A melhor solução para isso é criar uma instância de classe de aplicativo global e chamá-la no fragmento específico em que sua atividade não está sendo anexada

como abaixo

icon = MyApplication.getInstance().getString(R.string.weather_thunder);

Aqui está a classe da aplicação

public class MyApplication extends Application {

    private static MyApplication mInstance;
    private RequestQueue mRequestQueue;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized MyApplication getInstance() {
        return mInstance;
    }
}
md gouse
fonte
1
Sim, esse método também é amplamente utilizado.
CoolMind 07/12
1
Esta não é uma opção inteligente. FragmentContext e ApplicationContext têm estilos diferentes. O Contexto do Fragmento pode ter um tema escuro, estilo personalizado, Localidade etc. Enquanto ApplicationContext não pode puxar recurso correto. Se você não possui o Contexto, não deve tentar renderizar esse recurso.
Jemshit Iskenderov 01/06
2

Este erro pode ocorrer se você estiver instanciando um fragmento que de alguma forma não possa ser instanciado:

Fragment myFragment = MyFragment.NewInstance();


public classs MyFragment extends Fragment {
  public void onCreate() {
   // Some error here, or anywhere inside the class is preventing it from being instantiated
  }
}

No meu caso, eu encontrei isso quando tentei usar:

private String loading = getString(R.string.loading);
sagits
fonte
2

No uso de fragmentos isAdded() ele retornará verdadeiro se o fragmento estiver atualmente anexado à Atividade.

Se você deseja verificar dentro da Atividade

 Fragment fragment = new MyFragment();
   if(fragment.getActivity()!=null)
      { // your code here}
      else{
       //do something
       }

Espero que ajude alguém

Prateek218
fonte
1

Adotei a seguinte abordagem para lidar com esse problema. Criou uma nova classe que atua como invólucro para métodos de atividade como este

public class ContextWrapper {
    public static String getString(Activity activity, int resourceId, String defaultValue) {
        if (activity != null) {
            return activity.getString(resourceId);
        } else {
            return defaultValue;
        }
    }

    //similar methods like getDrawable(), getResources() etc

}

Agora, onde quer que eu precise acessar recursos de fragmentos ou atividades, em vez de chamar diretamente o método, eu uso essa classe. Caso a atividade contextnão seja, nullela retorna o valor do ativo e, caso contextseja nulo, passa um valor padrão (que também é especificado pelo responsável pela chamada da função).

Importante Esta não é uma solução, é uma maneira eficaz de lidar com essa falha normalmente. Você deseja adicionar alguns logs nos casos em que você está obtendo uma instância de atividade como nula e tentar corrigir isso, se possível.

Ezio
fonte
0

isso acontece quando o fragmento não possui um contexto, portanto, o método getActivity () retorna nulo. verifique se você usa o contexto antes de obtê-lo , ou se a Atividade não existe mais. use context in fragment.onCreate e após a resposta da API geralmente, esse problema ocorre

fã dexian
fonte
0

Às vezes, essa exceção é causada por um erro na implementação da biblioteca de suporte. Recentemente, tive que fazer o downgrade de 26.1.0 para 25.4.0 para me livrar dele.

Bord81
fonte
Não, não, mas talvez eu deva criar um.
precisa saber é o seguinte
0

Esse problema ocorre sempre que você chama um contexto indisponível ou nulo quando o chama. Pode ser uma situação quando você está chamando o contexto do segmento de atividade principal em um segmento de segundo plano ou o contexto do segmento de segundo plano no segmento de atividade principal.

Por exemplo, atualizei minha sequência de preferências compartilhadas como a seguir.

editor.putString("penname",penNameEditeText.getText().toString());
editor.commit();
finish();

E chamou finish () logo depois. Agora, o que ele faz é que, como commit, execute no thread principal e interrompa qualquer outro commit do Async, se chegar até ele terminar. Portanto, seu contexto permanece ativo até a gravação ser concluída. Portanto, o contexto anterior está ativo, causando o erro.

Portanto, verifique seu código novamente se houver algum código com esse problema de contexto.

Prashant Paliwal
fonte
como você conseguiu resolver esse problema? Estou chamando-o em um segmento assíncrono e estou enfrentando esse problema agora.
19718 Simon
Apenas certifique-se de que a operação de gravação esteja concluída, apenas o contexto será eliminado antes da conclusão da operação de gravação.
Prashant Paliwal