Chiamata startActivity () dall'esterno di un contesto Activity


368

Ho implementato un ListViewnella mia applicazione Android. Mi associo a questo ListViewusando una sottoclasse personalizzata della ArrayAdapterclasse. All'interno del ArrayAdapter.getView(...)metodo ignorato , assegno un OnClickListener. Nel onClickmetodo di OnClickListener, voglio avviare una nuova attività. Ottengo l'eccezione:

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

Come posso ottenere Contextche la ListView(corrente Activity) stia funzionando?


1
Penso che la risposta di Alex dovrebbe essere la soluzione 'accettata' al tuo problema, poiché corregge l'errore che hai citato in modo più generico
devanshu_kaushik,

10
Adoro che "È davvero quello che vuoi?" ... Ho ricevuto un messaggio prima che dicesse "Sei sicuro di non aver dimenticato di annullare la registrazione di un ricevitore di trasmissione da qualche parte?" ECCEZIONALE! Tanto di cappello a chiunque metta tutti questi piccoli messaggi per aiutarci a litigare.
Nerdy Bunz,

1
Ho incontrato questo problema. quando ho aggiornato targetSdkVersion a 28.
illusionJJ

Risposte:


575

O

  • memorizzare nella cache l'oggetto Context tramite la funzione di costruzione nell'adattatore oppure
  • ottenerlo dal tuo punto di vista.

O come ultima risorsa,

  • aggiungi - FLAG_ACTIVITY_NEW_TASK flag al tuo intento:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Modifica: eviterei di impostare flag in quanto interferirebbe con il normale flusso di eventi e cronologia.


6
Che dire della funzione AutoLink di TextView in cui non riesco a controllare gli Intenti (e quindi i flag) creati dal sistema?
Alex Semeniuk,

75
Stavo ottenendo questa eccezione quando stavo facendo qualcosa di simile context.startActivity(intent);Ho appena cambiato contextda ApplicationContexta Activitytipo. Ciò ha risolto il problema.
Sufian,

@AlexSemeniuk ha mai trovato una soluzione?

@AlexSemeniuk - autoLink funzionerà finché passerai l'attività come contesto all'adattatore
Georges,

Ho passato l'oggetto Context tramite il costruttore ma non funziona. ma FLAG_ACTIVITY_NEW_TASK funziona molto bene per me grazie.
Hiren,

100

Puoi ottenerlo con addFlags anzichésetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Secondo la documentazione fa:

Aggiungi ulteriori flag all'intento (o con valore flag esistente).


MODIFICARE

Fai attenzione se stai utilizzando le bandiere per modificare lo stack della cronologia come dice la risposta di Alex Volovoy :

... evita di impostare flag in quanto interferirà con il normale flusso di eventi e cronologia.


1
Ho un problema molto simile. Hai riscontrato problemi con lo stack della cronologia o qualcos'altro come suggerito dalle risposte sopra?
Einar Sundgren,

1
Non sono esattamente sicuro di quello che stai cercando, ma puoi iniziare un'attività senza una storia del genere: Intent intent = new Intent (Intent.ACTION_VIEW, "http: \\ www.google.com")); intent. addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (intento);
Bruno Bieri,

Perché non è consigliabile aggiungere qui i flag? Quanto è fondamentale interferire con il normale flusso di eventi e stack di cronologia?
Jason Krs

@JasonKrs puoi usare addFlags. Basta essere consapevoli del fatto che è possibile modificare lo stack della cronologia in base alla bandiera aggiunta. FLAG_ACTIVITY_NEW_TASK può essere utilizzato in questa situazione. Per maggiori dettagli leggi: developer.android.com/reference/android/content/…
Bruno Bieri


40

Se hai riscontrato un errore a causa dell'utilizzo di crea selettore come di seguito:

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"));

Imposta il flag per creare selettore in questo modo:

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
È stato molto utile L'intenzione esattamente più selettiva dovrebbe avere questa bandiera!
Mahdi,

2
Questa è la soluzione corretta, ed esattamente cosa bisogna fare, new_task in intent.chooser
Rafael Guimarães,

15

Inoltre: se mostri i collegamenti in listview in frammenti , non crearli in questo modo

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

invece chiama

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

l'adattatore funziona bene in entrambi i casi, ma i collegamenti funzionano solo nell'ultimo.


@utente2676468: questo ha risolto il problema del collegamento automatico per me.
Head Geek,

Questa dovrebbe essere una risposta accettata, invece di usare le bandiere è meglio !!
Gastón Saillén,

@ GastónSaillén, non uso getApplicationContext()(tranne l'inizializzazione dell'applicazione), ma ho colto questa eccezione. Quindi, le situazioni possono essere diverse.
CoolMind,

Questo era il mio problema, ho usato getApplicationContext () per il contesto. L'impostazione thiscome contesto funziona in relazione all'attività corrente.
Brlja,

14

Penso che forse stai implementando OnClickListener nel posto sbagliato - di solito dovresti sicuramente implementare un OnItemClickListener nella tua attività e impostarlo su ListView, altrimenti potresti avere problemi con i tuoi eventi ...


2
Mi porti alla soluzione. Avevo bisogno di usare un OnItemClickListener, assegnato a ListView. Ecco alcuni link per chiunque altro: developer.android.com/reference/android/widget/… androidpeople.com/… Grazie per l'aiuto.
Sako73,

Fornisci risposte generiche. La risposta di Alex Volovoy di seguito risolve il problema in modo generico.
devanshu_kaushik,

Per i posteri: se lo definisci direttamente come setListener (nuovo listener) su un componente richiede un contesto, crei un riferimento implicito all'intera attività che perderà memoria come non crederesti. Questo può essere aggirato creando un listener di classe interno statico o spostando il listener in una classe separata se deve essere in grado di gestire input da più di un'origine.
G_V

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

o

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

cambia in basso

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

Alla 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?");
}

Quindi il modo migliore è aggiungere 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);

Ciò è necessario per dispositivi a 28 e superiori.
Md Mohsin,

7

Vedi, se stai creando un intento all'interno di un listener in qualche metodo

override onClick (View v).

quindi chiama il contesto anche da questa vista:

v.getContext ()

Non ci sarà nemmeno bisogno di SetFlags ...


E quale era la situazione sbagliata? v.getApplicationContext ()?
CoolMind,


3

Elaborare la risposta di Alex Volovoy ancora un po '-

nel caso in cui si riscontri questo problema con i frammenti, getActivity () funziona bene per ottenere il contesto

In altri casi:

Se non vuoi usare-

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

quindi fai una funzione come questa nella tua OutsideClass -

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

Ora, nella tua attività principale ogni volta che fai una nuova OutsideClass chiama il metodo sopra immediatamente dopo aver definito la OutsideClass dando il contesto dell'attività come argomento. Anche nella tua attività principale fai una funzione-

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

ora ritorna al tuo OutsideClass e per iniziare nuove attività fai qualcosa del genere-

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

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

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

In questo modo sarai in grado di avviare diverse attività chiamate da diversi OutsideClass senza incasinare le bandiere.

Nota: prova a non memorizzare nella cache l'oggetto di contesto tramite il costruttore per il frammento (con adattatore, va bene). Un frammento dovrebbe avere un costruttore vuoto, altrimenti l'applicazione si arresta in modo anomalo in alcuni scenari.

ricordati di chiamare

OutsideClass.gettingContext(Context context);

anche nella funzione onResume ().


3

Questo errore si verifica quando l'inattività non sa quale sia la sua attività. Quindi è necessario aggiungere attività prima di startActivity ()

devi impostare

context.startActivity(yourIntent);

Se chiami startActivityda Fragment, un chiamante può spesso essere un frammento, non un'attività.
CoolMind,

2

Secondo me, è meglio usare il metodo di startActivity()solo nel tuo codice di Activity.class. Se lo usi Adapternell'altra classe o, ne risulterà.


2

Ho anche avuto lo stesso problema. Controlla tutto il contesto che hai superato. Per i " collegamenti " è necessario il contesto di attività e non il contesto di applicazione .

Questo è il posto dove dovresti controllare:

1.) Se hai utilizzato LayoutInflater controlla quale contesto hai superato.

2.) Se si utilizza un adattatore verificare quale contesto è stato superato.


2

Ho avuto lo stesso problema. Il problema è con il contesto. Se si desidera aprire qualsiasi collegamento (ad esempio condividere qualsiasi collegamento tramite selettore), passare il contesto dell'attività, non il contesto dell'applicazione.

Non dimenticare di aggiungere myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)se non sei nella tua attività.


2

Usa questo codice in Adapter_Activity e usa context.startActivity(intent_Object)eintent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Come questo:

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

Funziona....


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

Spero che funzioni.


1

Di fronte allo stesso problema poi implementato

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

e ho risolto il problema.

Potrebbe esserci un altro motivo correlato all'adattatore di visualizzazione elenco.
Puoi vedere questo blog , descritto molto bene.


blog utile, grazie. :)
Rucha Bhatt Joshi,

1

Usa questo codice Funziona bene per me. Condividi qualcosa dall'esterno di un'attività:

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);

L'impostazione delle bandiere incasina la storia dello stacktrace
Ezio,

1

Poiché l'aggiunta di flag influisce event_flowed stack_historyè meglio passare il "contesto dell'applicazione" alla non attività da cui è necessario chiamare una classe di attività nel modo seguente:

"ActivityClassName.this" (Mentre si passa il contesto in questo modo, conterrà tutti i dettagli e le informazioni necessari per chiamare un'attività da uno scenario non di attività)

Quindi non è necessario impostare o aggiungere flag, funzionerà perfettamente in ogni caso.


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

0

Se stai invocando Share Intent nel plug-in Cordova, l'impostazione di Flag non aiuta. Invece usa questo -

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

0

La mia situazione era un po 'diversa, sto testando la mia app usando Espressoe ho dovuto avviare la mia attività ActivityTestRuledalla strumentazione Context(che non è quella proveniente da un Activity).

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

Ho dovuto cambiare i flag e aggiungerne un orbit per bit ( |in Java) conIntent.FLAG_ACTIVITY_NEW_TASK

Quindi risulta in:

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

0

Versione di Kotlin

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.