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.