O fragmento onAttach () do Android foi descontinuado

326

Atualizei meu aplicativo para usar a biblioteca de suporte mais recente (versão 23.0.0). Descobri que eles preteriram a função onAttach () da classe Fragment.

Ao invés de:

onAttach (Activity activity)

É neve:

onAttach (Context context)

Como meu aplicativo usa a atividade passada antes da depreciação, acho que uma possível solução é:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    activity = getActivity();
}

Essa seria a maneira correta de fazer isso?

ATUALIZAR:

Se eu executar um dispositivo com API menor que 23, o novo onAttach () nem será chamado. Espero que não seja isso que eles pretendam fazer!

ATUALIZAÇÃO 2:

O problema foi resolvido com as atualizações mais recentes do SDK.

Eu testei no meu dispositivo API 22 e onAttach (Context) está sendo chamado.

Clique aqui para seguir o relatório de erros que abri há algumas semanas e as respostas dos funcionários do Google.

TareK Khoury
fonte
Se você estiver usando métodos específicos de atividade de sua instância passada, já tentou converter o contexto para o de sua atividade? Lembrar Atividade é uma subclasse de Contexto. Talvez um elenco funcionasse.
precisa saber é o seguinte
por alguma razão, o onAttach () nem está sendo chamado! alguma ideia? você tentou atualizar para a última lib de suporte?
TareK Khoury
2
Por que a API mudou para Context? Você não precisa de um Activitypara anexar e exibir um fragmento de qualquer maneira? De que outra forma você usará o Contextparâmetro?
precisa saber é o seguinte
1
Eu o publiquei
TareK Khoury em 30/08/15
6
Para que o novo onAttach(Context context)seja chamado, você precisa usar um dispositivo que tenha pelo menos API 23 OU usar android.support.v4.app.Fragment. Veja aqui
nevzo 26/09/15

Respostas:

337

Atividade é um contexto, portanto, se você pode simplesmente verificar se o contexto é uma Atividade e transmiti-lo, se necessário.

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity a;

    if (context instanceof Activity){
        a=(Activity) context;
    }

}

Atualização: alguns estão alegando que a nova Contextsubstituição nunca é chamada. Eu fiz alguns testes e não consigo encontrar um cenário em que isso seja verdade e, de acordo com o código-fonte, nunca deve ser verdade. Em todos os casos que testei, antes e depois do SDK23, Activityas Contextversões e as onAttachforam chamadas. Se você puder encontrar um cenário em que esse não seja o caso, sugiro que você crie um projeto de exemplo ilustrando o problema e relate à equipe do Android .

Atualização 2: só uso os fragmentos da Biblioteca de Suporte Android, pois os bugs são corrigidos mais rapidamente lá. Parece que o problema acima, em que as substituições não são chamadas corretamente, só vem à tona se você usar os fragmentos da estrutura.

Kuffs
fonte
5
Não é realmente uma solução, pois onAttach com contexto não é chamado da mesma maneira que onAttach com atividade. Se você tiver algum código de inicialização no onAttach com uma atividade como parâmetro, essa alteração não funcionará.
21915 Buddy
2
Não, não funciona da mesma forma, pelo menos no meu caso. Não uso atividade nem contexto no onAttach, faço inicialização. Tentei substituir onAttach com atividade por outra com contexto e ele não é chamado da mesma maneira. Portanto, eles não são tão facilmente intercambiáveis.
21915 Buddy
7
Os mesmos problemas que Buddy tem ... onAttach(Context)nem parecem ser chamados.
Stéphane
2
Eu examinei meu código e posso verificar se é possível onAttach(context)não ser chamado.
Chad Bingham
2
No meu caso, o onAttach () não será chamado se reiniciarmos a atividade que foi limpa pelo sistema antes. Mas nem sempre é assim. Coloquei uma inicialização de um WeakReference no contexto onAttach (contexto de contexto), refActivity = new WeakReference <> ((AppCompatActivity)). E lança NullPointerException no onCreateView () ocasionalmente.
Kimi Chiu
45

Esta é outra grande mudança do Google ... A modificação sugerida: substituir onAttach(Activity activity)por onAttach(Context context)travar meus aplicativos em APIs mais antigas, pois onAttach(Context context)não será chamada em fragmentos nativos.

Eu estou usando os fragmentos nativos (android.app.Fragment), então tive que fazer o seguinte para fazê-lo funcionar novamente em APIs mais antigas (<23).

Aqui está o que eu fiz:

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    // Code here
}

@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        // Code here
    }
}
Yoann Hercouet
fonte
Sr.Yoann Hercouet, você pode explicar como fazê-lo acima da API 23, por favor me ajude, obrigado desde já, E / AndroidRuntime: FATAL EXCEPTION: main, java.lang.ClassCastException: com.ual.SMS_Activity@afd5683, no android. support.v4.app.FragmentManagerImpl.moveToState, em android.support.v4.app.FragmentManagerImpl.execSingleAction. Aqui eu postei as linhas necessárias que você vai conhecer o meu bug.
Mohanraj S
@MohanRajS É o mesmo na API 24 (a que eu usei), de acordo com seu código, seu problema parece não ter nada a ver com isso.
Yoann Hercouet
@YoannHercouet, Obrigado pela sua resposta, deixe-me verificar e atualizar.
Mohanraj S
1
Você não está satisfeito com o Google por causa da dificuldade de segmentar APIs mais antigas. Bem, considere a bênção que você PODE direcionar para APIs mais antigas, enquanto a Apple, por exemplo, o prejudicaria tremendamente e o forçaria a apoiar apenas os mais novos.
Stan
39

Se você usar os fragmentos da estrutura e a versão do SDK do dispositivo for menor que 23, OnAttach(Context context)não será chamado.

Eu uso fragmentos de suporte, então a depreciação é corrigida e onAttach(Context context)sempre é chamada.

kikermo
fonte
11

Atualmente, a partir do onAttachcódigo do fragmento, não está claro se essa Contexté a atividade atual: código-fonte

public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

Se você der uma olhada getActivity, verá a mesma chamada

/**
 * Return the Activity this fragment is currently associated with.
 */
final public Activity getActivity() {
    return mHost == null ? null : mHost.getActivity();
}

Portanto, se você quiser ter certeza de que está recebendo a Atividade, use getActivity()( onAttachno seu Fragment), mas não se esqueça de verificar nullporque, se mHostfor, nullsua atividade seránull

royB
fonte
6
@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity activity = context instanceof Activity ? (Activity) context : null;
}
trabalhou
fonte
5

Embora pareça que na maioria dos casos é suficiente onAttach(Context), existem alguns telefones (por exemplo: Xiaomi Redme Note 2) onde não está sendo chamado, portanto, causa NullPointerExceptions. Portanto, para garantir a segurança, sugiro deixar o método obsoleto também:

// onAttach(Activity) is necessary in some Xiaomi phones
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    _onAttach(activity);
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    _onAttach(context);
}

private void _onAttach(Context context) {
    // do your real stuff here
}
Gavriel
fonte
3

Baixe a mais nova biblioteca de suporte com o gerenciador sdk e inclua

compile 'com.android.support:appcompat-v7:23.1.1'

no gradle.app e defina a versão de compilação como api 23

Essah
fonte
1

A resposta abaixo está relacionada a este aviso de descontinuação que ocorre no tutorial Fragmentos no site do desenvolvedor do Android e pode não estar relacionado às postagens acima.

Eu usei esse código na lição do tutorial e funcionou.

public void onAttach(Context context){
    super.onAttach(context);

    Activity activity = getActivity();

Eu estava preocupado que a atividade talvez fosse nula como afirma a documentação.

getActivity

FragmentActivity getActivity () Retorne a FragmentActivity à qual este fragmento está associado atualmente. Pode retornar nulo se o fragmento estiver associado a um contexto.

Mas o onCreate no main_activity mostra claramente que o fragmento foi carregado e, após esse método, chamar a atividade get do fragmento retornará a classe main_activity.

getSupportFragmentManager (). beginTransaction () .add (R.id.fragment_container, firstFragment) .commit ();

Espero estar certo com isso. Eu sou um novato absoluto.

Roy Selim
fonte
1

você provavelmente está usando android.support.v4.app.Fragment. Para isso, em vez de onAttachmétodo, basta usar getActivity()para obter a FragmentActivityque o fragmento está associado. Caso contrário, você poderia usar o onAttach(Context context)método

LeoCoder
fonte
0

Isso funcionou para mim quando eu defini a Interface 'TopSectionListener', seu objeto command de atividade:

  //This method gets called whenever we attach fragment to the activity
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    Activity a=getActivity();
    try {
        if(context instanceof Activity)
           this.activitycommander=(TopSectionListener)a;
    }catch (ClassCastException e){
        throw new ClassCastException(a.toString());}

}
Muskan Agarwal
fonte