Aufruf von startActivity () von außerhalb eines Aktivitätskontexts


367

Ich habe eine ListViewin meiner Android-Anwendung implementiert . Ich binde daran ListViewmit einer benutzerdefinierten Unterklasse der ArrayAdapterKlasse. Innerhalb der überschriebenen ArrayAdapter.getView(...)Methode weise ich eine zu OnClickListener. In der onClickMethode von OnClickListenermöchte ich eine neue Aktivität starten. Ich bekomme die Ausnahme:

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

Wie kann ich das bekommen, unter dem Contextder ListView(der aktuelle Activity) arbeitet?


1
Ich denke, Alex 'Antwort sollte die "akzeptierte" Lösung für Ihr Problem sein, da sie den von Ihnen erwähnten Fehler allgemeiner
behebt

10
Ich liebe das "Ist es wirklich das, was du willst?" ... Ich hatte vorher eine Nachricht mit dem Titel "Sind Sie sicher, dass Sie nicht vergessen haben, irgendwo die Registrierung eines Rundfunkempfängers aufzuheben?" GENIAL! Hut ab vor dem, der all diese kleinen Nachrichten reingelegt hat, um uns zu helfen.
Nerdy Bunz

1
Ich habe dieses Problem getroffen. als ich targetSdkVersion auf 28 aktualisiert habe.
illusionJJ

Antworten:


574

Entweder

  • das Context-Objekt über den Konstruktor in Ihrem Adapter zwischenspeichern oder
  • Holen Sie es sich aus Ihrer Sicht.

Oder als letztes Mittel,

  • add - FLAG_ACTIVITY_NEW_TASK Flag zu Ihrer Absicht:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Bearbeiten - Ich würde das Setzen von Flags vermeiden, da dies den normalen Ablauf des Ereignis- und Verlaufsstapels stört.


6
Was ist mit der AutoLink- Funktion von TextView, bei der ich die vom System erstellten Absichten (und damit Flags) nicht steuern kann?
Alex Semeniuk

75
Ich war immer diese Ausnahme , wenn ich so etwas wie dies zu tun war context.startActivity(intent);ich gerade geändert contextvon ApplicationContextzu ActivityArt. Dies hat das Problem behoben.
Sufian

@AlexSemeniuk jemals eine Lösung gefunden?

@AlexSemeniuk - AutoLink funktioniert, solange Sie die Aktivität als Kontext an den Adapter übergeben
Georges

Ich habe das Context-Objekt über den Konstruktor übergeben, aber es funktioniert nicht. aber FLAG_ACTIVITY_NEW_TASK funktioniert sehr gut für mich, danke.
Hiren

100

Sie können dies mit addFlags anstelle von erreichensetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Laut Dokumentation gilt Folgendes:

Fügen Sie der Absicht zusätzliche Flags hinzu (oder mit dem vorhandenen Flags-Wert).


BEARBEITEN

Beachten Sie, wenn Sie Flags verwenden, dass Sie den Verlaufsstapel ändern, wie in der Antwort von Alex Volovoy angegeben :

... vermeiden Sie das Setzen von Flags, da dies den normalen Ablauf des Ereignis- und Verlaufsstapels stört.


1
Ich habe ein sehr ähnliches Problem. Haben Sie Probleme mit dem Verlaufsstapel oder etwas anderem gehabt, wie die obigen Antworten vermuten lassen?
Einar Sundgren

1
Ich bin mir nicht ganz sicher, wonach Sie suchen, aber Sie können eine Aktivität ohne einen solchen Verlauf starten: Absichtsabsicht = neue Absicht (Intent.ACTION_VIEW, "http: \\ www.google.com")); Absicht. addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (Absicht);
Bruno Bieri

Warum wird es nicht empfohlen, hier Flaggen hinzuzufügen? Wie wichtig ist es, den normalen Ablauf des Ereignis- und Verlaufsstapels zu stören?
Jason Krs

@JasonKrs können Sie addFlags verwenden. Beachten Sie jedoch, dass Sie den Verlaufsstapel abhängig von dem hinzugefügten Flag ändern können. In dieser Situation kann FLAG_ACTIVITY_NEW_TASK verwendet werden. Weitere Informationen finden Sie unter: developer.android.com/reference/android/content/…
Bruno Bieri


40

Wenn Sie aufgrund der Verwendung von create chooser wie unten einen Fehler erhalten haben:

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

Setzen Sie das Flag, um eine Auswahl wie folgt zu erstellen:

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
Es war sehr nützlich. Genau wählerische Absicht sollte diese Flagge haben!
Mahdi

2
Dies ist die richtige Lösung und genau das, was zu tun ist, new_task in intent.chooser
Rafael Guimarães

15

Außerdem: Wenn Sie Links in der Listenansicht in Fragmenten anzeigen , erstellen Sie sie nicht so

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

stattdessen anrufen

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

Der Adapter funktioniert in beiden Fällen einwandfrei, aber die Links funktionieren nur im letzten.


@ user2676468: Dies hat das Autolink-Problem für mich gelöst.
Head Geek

Dies sollte eine akzeptierte Antwort sein, anstatt Flags zu verwenden, ist dies besser !!
Gastón Saillén

@ GastónSaillén, ich benutze nicht getApplicationContext()(außer Anwendungsinitialisierung), habe aber diese Ausnahme abgefangen. Situationen können also anders sein.
CoolMind

Dies war mein Problem, ich habe getApplicationContext () für den Kontext verwendet. Das Festlegen thisals Kontext funktioniert in Bezug auf die aktuelle Aktivität.
Brlja

14

Ich denke, vielleicht implementieren Sie den OnClickListener an der falschen Stelle - normalerweise sollten Sie auf jeden Fall einen OnItemClickListener in Ihrer Aktivität implementieren und ihn stattdessen in der ListView festlegen, sonst treten Probleme mit Ihren Ereignissen auf ...


2
Sie führen mich zur Lösung. Ich musste einen OnItemClickListener verwenden, der der ListView zugewiesen war. Hier sind einige Links für andere: developer.android.com/reference/android/widget/… androidpeople.com/… Vielen Dank für die Hilfe.
Sako73

Bitte geben Sie allgemeine Antworten. Die Antwort von Alex Volovoy unten löst das Problem auf generische Weise.
devanshu_kaushik

Für die Nachwelt: Wenn Sie es direkt als setListener (neuer Listener) für eine Komponente definieren, für die ein Kontext erforderlich ist, erstellen Sie einen impliziten Verweis auf die gesamte Aktivität, wodurch Speicher verloren geht, wie Sie es nicht glauben würden. Dies kann umgangen werden, indem entweder ein statischer Listener für die innere Klasse erstellt wird oder der Listener in eine separate Klasse verschoben wird, wenn Eingaben von mehr als einem Ursprung verarbeitet werden müssen.
G_V

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

oder

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

nach unten wechseln

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

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

Der beste Weg ist also hinzufügen 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);

Dies ist für Geräte ab 28 erforderlich.
Md Mohsin

7

Überprüfen Sie, ob Sie in einer Methode eine Absicht innerhalb eines Listeners erstellen

override onClick (View v).

Rufen Sie dann auch den Kontext über diese Ansicht auf:

v.getContext ()

Es werden nicht einmal SetFlags benötigt ...


Und was war die falsche Situation? v.getApplicationContext ()?
CoolMind

3

Für alle, die dies auf Xamarin.Android (MonoDroid) erhalten, auch wenn StartActivity von der Aktivität aufgerufen wird - dies ist tatsächlich ein Xamarin-Fehler mit neuer ART-Laufzeit, siehe https://bugzilla.xamarin.com/show_bug.cgi?id=17630


Ja, Sie müssen nur das tun, was oben beschrieben wurde, aber der Wortlaut hat sich geändert ... intent.SetFlags (ActivityFlags.NewTask);
Luke Alderton

3

Die Antwort von Alex Volovoy etwas näher erläutern -

Falls dieses Problem mit Fragmenten auftritt, funktioniert getActivity () einwandfrei, um den Kontext abzurufen

In anderen Fällen:

Wenn Sie nicht verwenden möchten-

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

dann machen Sie eine Funktion wie diese in Ihrer OutsideClass -

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

Wenn Sie jetzt in Ihrer Hauptaktivität eine neue OutsideClass erstellen, rufen Sie die obige Methode sofort auf, nachdem Sie die OutsideClass definiert haben und den Kontext der Aktivität als Argument angegeben haben. Auch in Ihrer Haupttätigkeit machen Sie eine Funktion-

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

Kehren Sie jetzt zu Ihrer OutsideClass zurück, und um eine neue Aktivität zu starten, gehen Sie wie folgt vor:

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

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

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

Auf diese Weise können Sie verschiedene Aktivitäten starten, die von verschiedenen OutsideClass aufgerufen werden, ohne die Flags durcheinander zu bringen.

Hinweis: Versuchen Sie, das Kontextobjekt nicht über den Konstruktor für das Fragment zwischenzuspeichern (mit Adapter, es ist in Ordnung). Ein Fragment sollte einen leeren Konstruktor haben, da sonst die Anwendung in einigen Szenarien abstürzt.

Denken Sie daran, anzurufen

OutsideClass.gettingContext(Context context);

auch in der Funktion onResume ().


3

Dieser Fehler tritt auf, wenn die Startaktivität nicht weiß, welche Aktivität er hat. Sie müssen also vor startActivity () Aktivität hinzufügen.

Sie müssen einstellen

context.startActivity(yourIntent);

Wenn Sie rufen startActivityaus Fragment, kann ein Anrufer oft ein Fragment sein, nicht eine Aktivität.
CoolMind

2

Meiner Meinung nach ist es besser, die Methode startActivity()nur in Ihrem Code des zu verwenden Activity.class. Wenn Sie das in der Adapteroder einer anderen Klasse verwenden, führt dies dazu.


2

Ich hatte auch das gleiche Problem. Überprüfen Sie den gesamten Kontext, den Sie übergeben haben. Für ' Links ' wird der Aktivitätskontext und nicht der Anwendungskontext benötigt .

Dies ist der Ort, an dem Sie Folgendes überprüfen sollten:

1.) Wenn Sie LayoutInflater verwendet haben, überprüfen Sie, welchen Kontext Sie übergeben haben.

2.) Wenn Sie einen Adapter verwenden, überprüfen Sie, welchen Kontext Sie übergeben haben.


2

Ich hatte das gleiche Problem. Das Problem liegt im Kontext. Wenn Sie Links öffnen möchten (z. B. einen Link über die Auswahl freigeben möchten), übergeben Sie den Aktivitätskontext und nicht den Anwendungskontext.

Vergessen myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)Sie nicht hinzuzufügen, wenn Sie nicht in Ihrer Aktivität sind.


2

Verwenden Sie diesen Code in Ihrer Adapter_Activity und verwenden Sie context.startActivity(intent_Object)undintent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

So was:

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

Es klappt....


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

Ich hoffe das wird funktionieren.


1

Konfrontiert das gleiche Problem dann implementiert

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

und habe das Problem gelöst.

Es kann einen anderen Grund geben, der mit dem Listenansichtsadapter zusammenhängt.
Sie können diesen Blog sehen , der sehr gut beschrieben wurde.


hilfreicher Blog, danke. :)
Rucha Bhatt Joshi

1

Verwenden Sie diesen Code. Funktioniert gut für mich. Teilen Sie etwas von außerhalb einer Aktivität:

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

Das Einrichten von Flaggen bringt die Stacktrace-Geschichte durcheinander
Ezio

1

Da das Hinzufügen von Flags Auswirkungen hat event_flowund stack_historyes besser ist, den 'Anwendungskontext' an die Nichtaktivität zu übergeben, von wo aus Sie eine Aktivitätsklasse auf folgende Weise aufrufen müssen:

"ActivityClassName.this" (Während Sie den Kontext auf diese Weise übergeben, enthält er alle Details und Informationen, die Sie zum Aufrufen einer Aktivität aus einem Nicht-Aktivitätsszenario benötigen.)

Es ist also nicht erforderlich, Flags zu setzen oder hinzuzufügen. Dies funktioniert in jedem Fall einwandfrei.


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

0

Wenn Sie Share Intent im Cordova-Plugin aufrufen, hilft das Setzen des Flags nicht. Verwenden Sie stattdessen diese -

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

0

Meine Situation war etwas anders, ich teste meine App mit Espressound musste meine Aktivität mit ActivityTestRuleder Instrumentierung starten Context(die nicht von einer stammt Activity).

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

Ich musste die Flags ändern und ein orbitweises ( |in Java) mit hinzufügenIntent.FLAG_ACTIVITY_NEW_TASK

Daraus ergibt sich:

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

0

Kotlin-Version

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.