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?

Sako73
źródło
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.

Alex Volovoy
źródło
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.

Bruno Bieri
źródło
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,
64

Zamiast używać (getApplicationContext)useYourActivity.this

Jeffrey Nyauke
źródło
To zadziałało dla mnie, tj. activity.startActivityZamiastcontext.startActivity
Phani Rithvij,
NAJLEPSZA ODPOWIEDŹ!
amirhossein
To działa dla mnie.
user5722540
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);
sanath_p
źródło
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.

djdance
źródło
@ 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 ...

mreichelt
źródło
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);
Murtaza Ashraf
źródło
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);
Alen Lee
źródło
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 ...

Paulo Linhares - Packapps
źródło
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

Rouen
źródło
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 ().

Flying Monkey
źródło
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);
Cabezas
źródło
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.

kaosmys
źródło
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ś.

codemaniac
źródło
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.

Coder29
źródło
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....

Gaurav Lambole
źródło
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.

Chirag Patel
źródło
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ł.

Mayank Sharma
źródło
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);
Pooya Hayati
źródło
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.

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

Wersja Kotlin

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
Sazzad Hissain Khan
źródło