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?

Sako73
quelle
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.

Alex Volovoy
quelle
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.

Bruno Bieri
quelle
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
64

Anstatt Verwendung zu (getApplicationContext)verwendenYourActivity.this

Jeffrey Nyauke
quelle
Dies funktionierte für mich, dh activity.startActivityanstelle voncontext.startActivity
Phani Rithvij
DIE BESTE ANTWORT!
Amirhossein
Das funktioniert bei mir.
user5722540
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);
sanath_p
quelle
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.

djdance
quelle
@ 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 ...

mreichelt
quelle
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);
Murtaza Ashraf
quelle
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);
Alen Lee
quelle
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 ...

Paulo Linhares - Packapps
quelle
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

Rouen
quelle
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 ().

Fliegender Affe
quelle
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);
Cabezas
quelle
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.

Kaosmys
quelle
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.

codemaniac
quelle
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.

Coder29
quelle
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....

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

Ich hoffe das wird funktionieren.

Chirag Patel
quelle
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.

Mayank Sharma
quelle
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);
Pooya Hayati
quelle
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.

Musthafa
quelle
0
Intent i= new Intent(context, NextActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
Chandan Lal
quelle
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"));
Sandeep Kumar
quelle
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)
Rafael Ruiz Muñoz
quelle
0

Kotlin-Version

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Sazzad Hissain Khan
quelle