Chamando startActivity () de fora de um contexto de Atividade


368

Eu implementei um ListViewno meu aplicativo Android. Eu vinculo a isso ListViewusando uma subclasse personalizada da ArrayAdapterclasse. Dentro do ArrayAdapter.getView(...)método substituído , eu atribuo um OnClickListener. No onClickmétodo do OnClickListener, quero iniciar uma nova atividade. Eu recebo a exceção:

Calling startActivity() from outside of an Activity  context requires the  
FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

Como posso obter o Contextque o ListView(o atual Activity) está trabalhando?


11
Eu acho que a resposta de Alex deve ser a solução 'aceito' para o seu problema, uma vez que corrige o erro que você mencionou de forma mais genérica
devanshu_kaushik

10
Eu amo que "é realmente isso que você quer?" ... Antes, recebi uma mensagem dizendo "Tem certeza de que não se esqueceu de cancelar o registro de um receptor de transmissão em algum lugar?" IMPRESSIONANTE! Tiramos o chapéu para quem colocar todas essas pequenas mensagens para nos ajudar a brigar.
Nerdy Bunz

11
Eu conheci esse problema. Quando atualizei o targetSdkVersion para 28. #
illusionJJ

Respostas:


575

Ou

  • armazenar em cache o objeto Context via construtor em seu adaptador ou
  • obtenha-o da sua vista.

Ou, como último recurso,

  • adicione - sinalizador FLAG_ACTIVITY_NEW_TASK à sua intenção:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Editar - eu evitaria definir sinalizadores, pois isso interfere no fluxo normal da pilha de eventos e histórico.


6
E o recurso autoLink do TextView, onde não consigo controlar o Intent (e, portanto, os sinalizadores) criados pelo sistema?
Alex Semeniuk

75
Eu estava recebendo essa exceção quando eu estava fazendo algo parecido com isso context.startActivity(intent);eu só mudou contexta partir ApplicationContextde Activitytipo. Isso resolveu o problema.
Sufian

@AlexSemeniuk já encontrou uma solução?

@AlexSemeniuk - autoLink vai trabalhar enquanto você passar a atividade como contexto para o adaptador
Georges

Passei o objeto de contexto via construtor, mas não funciona. mas FLAG_ACTIVITY_NEW_TASK funciona muito bem para mim, obrigado.
Hiren

100

Você pode conseguir isso com addFlags em vez desetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

De acordo com a documentação, ele faz:

Adicione sinalizadores adicionais à intenção (ou com o valor dos sinalizadores existentes).


EDITAR

Esteja ciente de que, se você estiver usando sinalizadores, altera a pilha do histórico, como diz a resposta de Alex Volovoy :

... evite definir sinalizadores, pois isso interferirá no fluxo normal de eventos e na pilha de histórico.


11
Eu tenho um problema muito similar. Você já teve algum problema com a pilha do histórico ou qualquer outra coisa, como as respostas acima sugerem?
Einar Sundgren

11
Não sei exatamente o que você está procurando, mas é possível iniciar uma atividade sem um histórico como esse: Intent intent = new Intent (Intent.ACTION_VIEW, "http: \\ www.google.com")); intent. addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (intenção);
Bruno Bieri

Por que não é recomendável adicionar aquiFlags? Quão crítico é interferir no fluxo normal de eventos e na pilha de histórico?
Jason Krs

@JasonKrs você pode usar addFlags. Lembre-se de que você pode alterar a pilha do histórico, dependendo da sinalização que adicionar. O FLAG_ACTIVITY_NEW_TASK pode ser usado nesta situação. Para mais detalhes, leia: developer.android.com/reference/android/content/...
de Bruno Bieri


40

Se você recebeu um erro por usar o seletor de criação como abaixo:

Intent sharingIntent = new Intent(Intent.ACTION_VIEW);
sharingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sharingIntent.setData(Uri.parse("http://google.com"));
startActivity(Intent.createChooser(sharingIntent, "Open With"));

Defina o sinalizador para criar um seletor como este:

Intent sharingIntent = new Intent(Intent.ACTION_VIEW);
sharingIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sharingIntent.setData(Uri.parse("http://google.com"));

Intent chooserIntent = Intent.createChooser(sharingIntent, "Open With");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(chooserIntent);

4
Foi muito útil. A intenção exata do seletor deve ter essa bandeira!
Mahdi

2
Esta é a soluction correta, e exatamente o que tem que fazer, New_Task em intent.chooser
Rafael Guimarães

15

Além disso: se você mostrar links no listview no fragmento , não o crie assim

adapter = new ListAdapter(getActivity().getApplicationContext(),mStrings);

em vez disso chame

adapter = new ListAdapter(getActivity(),mStrings);

O adaptador funciona bem nos dois casos, mas os links funcionam apenas no último.


@ user2676468: isso resolveu o problema de vínculo automático para mim.
Head Geek

Esta deve ser uma resposta aceita, em vez de usar sinalizadores, é melhor !!
Gastón Saillén 18/11/19

@ GastónSaillén, eu não uso getApplicationContext()(exceto a inicialização do aplicativo), mas peguei essa exceção. Então, as situações podem ser diferentes.
CoolMind 02/07

Este foi o meu problema, usei getApplicationContext () para o contexto. Definir thiscomo contexto funciona no que se refere à atividade atual.
Brlja 3/01

14

Acho que talvez você esteja implementando o OnClickListener no lugar errado - geralmente você deve definitivamente implementar um OnItemClickListener em sua atividade e defini-lo no ListView, ou você terá problemas com seus eventos ...


2
Você me levou para a solução. Eu precisava usar um OnItemClickListener, atribuído ao ListView. Aqui estão alguns links para outras pessoas: developer.android.com/reference/android/widget/… androidpeople.com/… Obrigado pela ajuda.
Sako73

Forneça respostas genéricas. A resposta de Alex Volovoy abaixo resolve o problema de maneira genérica.
Devanshu_kaushik 15/10/12

Para a posteridade: se você defini-lo diretamente como setListener (novo Ouvinte) em um componente requer um Contexto, cria uma referência implícita para toda a atividade que vazará memória como você não acreditaria. Isso pode ser contornado criando um ouvinte de classe interna estática ou movendo o ouvinte para uma classe separada, se ele precisar manipular entradas de mais de uma origem.
G_V

9
CustomAdapter mAdapter = new CustomAdapter( getApplicationContext(), yourlist);

ou

Context mContext = getAppliactionContext();
CustomAdapter mAdapter = new CustomAdapter( mContext, yourlist);

mude para abaixo

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

Na Android 28(Android P)startActivity

if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
        && (targetSdkVersion < Build.VERSION_CODES.N
                || targetSdkVersion >= Build.VERSION_CODES.P)
        && (options == null
                || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
    throw new AndroidRuntimeException(
            "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
}

Então, a melhor maneira é adicionar FLAG_ACTIVITY_NEW_TASK

Intent intent = new Intent(context, XXXActivity.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);

Isso é necessário para dispositivos 28 e acima.
Md Mohsin

7

Veja, se você estiver criando uma intenção dentro de um listener em algum método

override onClick (View v).

em seguida, chame o contexto também por meio dessa visualização:

v.getContext ()

Nem será necessário SetFlags ...


E qual era a situação errada? v.getApplicationContext ()?
CoolMind 02/07

3

Para alguém que está conseguindo isso no Xamarin.Android (MonoDroid), mesmo quando StartActivity é chamado de atividade - esse é realmente um bug do Xamarin com o novo tempo de execução ART, consulte https://bugzilla.xamarin.com/show_bug.cgi?id=17630


Sim, você só precisa fazer o que foi descrito acima, mas o texto mudou ... intent.SetFlags (ActivityFlags.NewTask);
Luke Alderton

3

Elaborando um pouco mais a resposta de Alex Volovoy -

caso você esteja tendo esse problema com fragmentos, getActivity () funciona bem para obter o contexto

Em outros casos:

Se você não quiser usar-

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//not recommend

faça uma função como essa no seu OutsideClass -

public void gettingContext(Context context){
    real_context = context;//where real_context is a global variable of type Context
}

Agora, em sua atividade principal, sempre que você criar uma nova OutsideClass, chame o método acima imediatamente após definir o OutsideClass, fornecendo o contexto da atividade como argumento. Também em sua atividade principal, faça uma função

public void startNewActivity(final String activity_to_start) {
    if(activity_to_start.equals("ACTIVITY_KEY"));
    //ACTIVITY_KEY-is a custom key,just to
    //differentiate different activities
    Intent i = new Intent(MainActivity.this, ActivityToStartName.class);
    activity_context.startActivity(i);      
}//you can make a if-else ladder or use switch-case

agora volte para o OutsideClass e, para iniciar uma nova atividade, faça algo assim:

@Override
public void onClick(View v) {
........
case R.id.any_button:

            MainActivity mainAct = (MainActivity) real_context;             
            mainAct.startNewActivity("ACTIVITY_KEY");                   

        break;
    }
........
}

Dessa forma, você poderá iniciar atividades diferentes chamadas de OutsideClass diferentes sem mexer nos sinalizadores.

Nota: Tente não armazenar em cache o objeto de contexto via construtor para fragmento (com adaptador, tudo bem). Um fragmento deve ter um construtor vazio, caso contrário, o aplicativo trava em alguns cenários.

lembre-se de ligar

OutsideClass.gettingContext(Context context);

na função onResume () também.


3

Esse erro ocorre quando a atividade de inicialização não sabe qual é a atividade dele. Portanto, você deve adicionar atividades antes de startActivity ()

você deve definir

context.startActivity(yourIntent);

Se você chamar startActivitya partir de Fragment, um chamador pode muitas vezes ser um fragmento, não uma atividade.
CoolMind 02/07/19

2

Na minha opinião, é melhor usar o método startActivity()just no seu código do Activity.class. Se você usar isso na Adapterou em outra classe, isso resultará nisso.


2

Eu também tive o mesmo problema. Verifique todo o contexto que você passou. Para ' links ', ele precisa de Contexto de Atividade, não Contexto de Aplicativo .

Este é o local onde você deve verificar:

1.) Se você usou o LayoutInflater , verifique o contexto em que passou.

2.) Se você estiver usando algum adaptador, verifique em qual contexto você passou.


2

Eu tive o mesmo problema. O problema está no contexto. Se você deseja abrir qualquer link (por exemplo, compartilhar qualquer link através do seletor), passe o contexto da atividade, não o contexto do aplicativo.

Não se esqueça de adicionar myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)se você não estiver em sua atividade.


2

Use este código em seu Adapter_Activity e use context.startActivity(intent_Object)eintent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Como isso:

Intent n_act = new Intent(context, N_Activity.class);
n_act.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(n_act);

Funciona....


1
Intent viewIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);    
viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);    
startActivity(viewIntent);   

Eu espero que isso funcione.


1

Enfrentou o mesmo problema implementado

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

e foi resolvido o problema.

Pode haver outro motivo relacionado ao adaptador de exibição de lista.
Você pode ver este blog , descreveu-o muito bem.


blog útil, obrigado. :)
Rucha Bhatt Joshi

1

Use este código. Funciona bem para mim. Compartilhe algo de fora de uma atividade:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");

// Append Text
String Text = "Your Text Here"

intent.putExtra(Intent.EXTRA_TEXT, Text);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Intent shareIntent = Intent.createChooser(intent,"Share . . . ");
shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
G.context.getApplicationContext().startActivity(shareIntent);

Configurando bandeiras atrapalhar história stacktrace
Ezio

1

Como a adição de sinalizadores afeta event_flowe stack_historyé melhor passar o 'contexto do aplicativo' para a não atividade de onde você precisa chamar uma classe de atividade da seguinte maneira:

"ActivityClassName.this" (embora você passe o contexto dessa maneira, ele conterá todos os detalhes e informações necessários para chamar uma atividade de um cenário que não seja de atividade)

Portanto, não há necessidade de definir ou adicionar sinalizadores; isso funcionará bem em todos os casos.


0
Intent i= new Intent(context, NextActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);

0

Se você estiver chamando o compartilhamento de intenção no plug-in Cordova, a configuração do sinalizador não ajudará. Em vez disso, use isso -

cordova.getActivity().startActivity(Intent.createChooser(shareIntent, "title"));

0

Minha situação era um pouco diferente, estou testando meu aplicativo usando Espressoe tive que iniciar minha Atividade com ActivityTestRulea instrumentação Context(que não é a que vem de um Activity).

fun intent(context: Context) = 
    Intent(context, HomeActivity::class.java)
        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

Eu tive que mudar os sinalizadores e adicionar um orbit a bit ( |em Java) comIntent.FLAG_ACTIVITY_NEW_TASK

Portanto, resulta em:

fun intent(context: Context) = 
    Intent(context, HomeActivity::class.java)
        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)

0

Versão Kotlin

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.