Wywołanie startActivity () spoza kontekstu działania


367

Zaimplementowałem ListVieww mojej aplikacji na Androida. Wiążę się to ListViewprzy użyciu niestandardowego podklasę ArrayAdapterklasy. W przesłoniętej ArrayAdapter.getView(...)metodzie przypisuję OnClickListener. W onClickmetodzie OnClickListenerchcę rozpocząć nową działalność. Otrzymuję wyjątek:

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

Jak mogę uzyskać, Contextże ListView(bieżący Activity) działa?


1
Myślę, że odpowiedź Alexa powinna być „zaakceptowanym” rozwiązaniem twojego problemu, ponieważ
— naprawia

10
Uwielbiam to: „Czy naprawdę tego chcesz?” ... Miałem wcześniej wiadomość, że „Czy jesteś pewien, że nie zapomniałeś wyrejestrować gdzieś odbiornika?” NIESAMOWITE! Czapki z głów przed tym, kto umieszcza wszystkie te małe wiadomości, aby pomóc nam w kłótniach.
— Nerdy Bunz

1
Spotkałem ten problem. kiedy aktualizowane targetSdkVersion do 28.
— illusionJJ

Odpowiedzi:


574

Zarówno

  • buforować obiektu Context pośrednictwem konstruktora w karty, lub
  • weź to z twojego widoku.

Lub w ostateczności

  • dodaj - FLAG_ACTIVITY_NEW_TASK flagę do swoich celów:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Edytuj - unikałbym ustawiania flag, ponieważ zakłócałoby to normalny przepływ zdarzeń i stosu historii.


6
Co z funkcją autoLink TextView, w której nie mogę kontrolować zamiaru (a tym samym flag) tworzonego przez system?
— Alex Semeniuk

75
I był już ten wyjątek, gdy robiłem coś takiego context.startActivity(intent);po prostu zmieniło contextod ApplicationContextdo Activitytypu. To rozwiązało problem.
— Sufian

@AlexSemeniuk kiedykolwiek znalazł rozwiązanie?

@AlexSemeniuk - autoLink będzie działał, dopóki przekażesz aktywność jako kontekst do adaptera
— Georges

Obiekt kontekstu przekazałem przez konstruktor, ale nie działa. ale FLAG_ACTIVITY_NEW_TASK działa dla mnie bardzo dobrze, dzięki.
— Hiren

100

Możesz to osiągnąć za pomocą addFlags zamiastsetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Zgodnie z dokumentacją :

Dodaj dodatkowe flagi do intencji (lub z istniejącą wartością flagi).


EDYTOWAĆ

Pamiętaj, jeśli używasz flag, które zmieniają stos historii, ponieważ odpowiedź Alexa Volovoya mówi:

... unikaj ustawiania flag, ponieważ będą one zakłócały normalny przepływ zdarzeń i stosu historii.


1
Mam bardzo podobny problem. Czy napotkałeś jakieś problemy ze stosem historii lub cokolwiek innego, gdy powyższe odpowiedzi są najgorsze?
— Einar Sundgren,

1
Nie jestem do końca pewien, czego szukasz, ale możesz rozpocząć działanie bez historii: Intent intent = new Intent (Intent.ACTION_VIEW, „http: \\ www.google.com”)); intent. addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (intencja);
— Bruno Bieri,

Dlaczego nie zaleca się dodawania tutaj tagów? Jak krytyczne jest zakłócanie normalnego przepływu zdarzeń i stosu historii?
— Jason Krs,

@JasonKrs możesz użyć addFlags. Pamiętaj tylko, że możesz zmienić stos historii w zależności od dodanej flagi. W tej sytuacji można użyć FLAG_ACTIVITY_NEW_TASK. Aby uzyskać więcej informacji, przeczytaj: developer.android.com/reference/android/content/…
— Bruno Bieri,


40

Jeśli wystąpił błąd z powodu użycia opcji Utwórz selektor, jak poniżej:

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

Ustaw flagę, aby utworzyć selektor w ten sposób:

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
To było bardzo przydatne. Dokładnie wybór intencji powinien mieć tę flagę!
— Mahdi,

2
To poprawne rozwiązanie i dokładnie to, co trzeba zrobić, new_task in intent.chooser
— Rafael Guimarães

15

Ponadto: jeśli wyświetlasz fragmenty w widoku listy , nie twórz go w ten sposób

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

zamiast tego zadzwoń

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

adapter działa dobrze w obu przypadkach, ale linki działają tylko w ostatnim.


@ user2676468: to rozwiązało problem autolink dla mnie.
— Head Geek

To powinna być zaakceptowana odpowiedź, zamiast używać flag, lepiej !!
— Gastón Saillén

@ GastónSaillén, nie używam getApplicationContext()(oprócz inicjalizacji aplikacji), ale złapałem ten wyjątek. Tak więc sytuacje mogą być inne.
— CoolMind

To był mój problem, użyłem getApplicationContext () do kontekstu. Ustawienie thisjako kontekst działa, ponieważ odnosi się do bieżącej aktywności.
— Brlja

14

Myślę, że może wdrażasz OnClickListener w niewłaściwym miejscu - zwykle zdecydowanie powinieneś zaimplementować OnItemClickListener w swojej działalności i ustawić go na ListView, w przeciwnym razie wystąpią problemy ze swoimi zdarzeniami ...


2
Doprowadzasz mnie do rozwiązania. Musiałem użyć OnItemClickListener, przypisanego do ListView. Oto kilka linków dla każdego innego: developer.android.com/reference/android/widget/... androidpeople.com/... Dziękuję za pomoc.
— Sako73,

Proszę podać ogólne odpowiedzi. Poniższa odpowiedź Alex Volovoy rozwiązuje problem w sposób ogólny.
— devanshu_kaushik

Dla potomnych: Jeśli zdefiniujesz go bezpośrednio jako setListener (nowy Listener) w komponencie wymaga Kontekstu, utworzysz niejawne odniesienie do całej aktywności, która wycieknie z pamięci tak, jak byś nie uwierzył. Można to obejść, tworząc statyczny odbiornik klasy wewnętrznej lub przenosząc go do oddzielnej klasy, jeśli musi on obsługiwać dane wejściowe z więcej niż jednego źródła.
— G_V

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

lub

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

zmień na poniżej

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

Na początku Android 28(Android P)Aktywność

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

Więc najlepszym sposobem jest dodanie 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);

Jest to wymagane w przypadku urządzeń 28 i nowszych.
— Md Mohsin,

7

Zobacz, jeśli tworzysz zamiar w listiner w jakiś sposób

override onClick (View v).

następnie wywołaj kontekst również przez ten widok:

v.getContext ()

SetFlags nie będzie nawet potrzebny ...


A co było nie tak? v.getApplicationContext ()?
— CoolMind

3

Dla każdego, kto dostanie to na Xamarin.Android (MonoDroid), nawet gdy StartActivity jest wywoływana z aktywności - jest to właściwie błąd Xamarin z nowym środowiskiem uruchomieniowym ART, patrz https://bugzilla.xamarin.com/show_bug.cgi?id=17630


Tak, musisz po prostu postępować tak, jak opisano powyżej, ale brzmienie się zmieniło ... intent.SetFlags (ActivityFlags.NewTask);
— Luke Alderton

3

Opracowując nieco odpowiedź Alexa Volovoya -

w przypadku, gdy otrzymujesz ten problem z fragmentami, getActivity () działa dobrze, aby uzyskać kontekst

W innych sprawach:

Jeśli nie chcesz używać-

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

następnie utwórz taką funkcję w swoim OutsideClass -

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

Teraz, w swoim głównym działaniu, kiedy tylko tworzysz nową OutsideClass, wywołaj powyższą metodę natychmiast po zdefiniowaniu OutsideClass, podając kontekst działania jako argument. Również w swojej głównej działalności wykonaj funkcję

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

teraz wróć do klasy OutsideClass i zacznij nową aktywność, zrób coś takiego -

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

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

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

W ten sposób będziesz mógł rozpocząć różne działania wywoływane z różnych OutsideClass bez zepsucia się flagami.

Uwaga - Staraj się nie buforować obiektu kontekstowego za pomocą konstruktora dla fragmentu (z adapterem, jest w porządku). Fragment powinien mieć pusty konstruktor, w przeciwnym razie aplikacja ulega awarii w niektórych scenariuszach.

pamiętaj, aby zadzwonić

OutsideClass.gettingContext(Context context);

również w funkcji onResume ().


3

Ten błąd występuje, gdy startactivity nie wie, jaka jest jego aktywność. Musisz więc dodać aktywność przed startActivity ()

musisz ustawić

context.startActivity(yourIntent);

Jeśli dzwonisz startActivityz Fragment, dzwoniący często może być fragmentem, a nie działaniem.
— CoolMind

2

Moim zdaniem, lepiej jest użyć metody startActivity()właśnie w twoim kodzie Activity.class. Jeśli użyjesz tego w tej Adapterlub innej klasie, spowoduje to.


2

Też miałem ten sam problem. Sprawdź cały przekazany kontekst. Do „ linków ” potrzebny jest kontekst działania, a nie kontekst aplikacji .

To miejsce, w którym powinieneś sprawdzić:

1.) Jeśli użyłeś LayoutInflater, sprawdź, jaki kontekst przeszedłeś.

2.) Jeśli używasz adaptera, sprawdź, jaki kontekst przeszedłeś.


2

Miałem ten sam problem. Problem dotyczy kontekstu. Jeśli chcesz otworzyć dowolne linki (na przykład udostępnić dowolny link przez selektor), podaj kontekst działania, a nie kontekst aplikacji.

Nie zapomnij dodać, myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)jeśli nie jesteś w swojej działalności.


2

Użyj tego kodu w swojej Adapter_Activity i użyj context.startActivity(intent_Object)iintent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Lubię to:

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

To działa....


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

mam nadzieję, że to zadziała.


1

W obliczu tego samego problemu, a następnie wdrożony

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

i został rozwiązany problem.

Może istnieć inny powód związany z adapterem widoku listy.
Możesz zobaczyć Ten blog , bardzo dobrze go opisał.


pomocny blog, dziękuję. :)
— Rucha Bhatt Joshi

1

Użyj tego kodu. Działa dobrze dla mnie. Udostępnij coś spoza działania:

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

Ustawianie flag bałagan historia śledzenia stacktrace
— Ezio

1

Ponieważ dodanie flag wpływa event_flowi stack_historylepiej jest przekazać „kontekst aplikacji” do niedziałania, z którego należy wywołać klasę działania w następujący sposób:

„ActivityClassName.this” (podczas przekazywania kontekstu w ten sposób będzie on zawierał wszystkie szczegóły i informacje potrzebne do wywołania działania z scenariusza braku aktywności)

Nie ma więc potrzeby ustawiania ani dodawania flag, będzie to działać dobrze w każdym przypadku.


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

0

Jeśli wywołujesz zamiar udostępniania we wtyczce Cordova, ustawienie flagi nie pomoże. Zamiast tego użyj tego -

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

0

Moja sytuacja była trochę inna, testuję aplikację Espressoi musiałem uruchomić moją Aktywność za ActivityTestRulepomocą oprzyrządowania Context(które nie pochodzi od an Activity).

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

Musiałem zmienić flagi i dodać orbitowe ( |w Javie) za pomocąIntent.FLAG_ACTIVITY_NEW_TASK

Skutkuje to:

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

0

Wersja Kotlin

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.