Виклик startActivity () поза контекстом діяльності


367

Я реалізував ListViewу своєму додатку Android. Я пов'язую з цим ListViewза допомогою спеціального підкласу ArrayAdapterкласу. Всередині заміненого ArrayAdapter.getView(...)методу я призначаю ан OnClickListener. У onClickметоді програми OnClickListenerя хочу запустити нову діяльність. Я отримую виняток:

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

Як я можу зрозуміти, Contextщо працює ListView(струм Activity)?


1
Я думаю, що відповідь Алекса має бути «прийнятим» рішенням вашої проблеми, оскільки вона виправляє помилку, яку ви згадали, більш загальним чином
devanshu_kaushik

10
Мені подобається, що "Це справді те, чого ти хочеш?" ... У мене раніше було повідомлення про те, що "Ви впевнені, що не забули де-небудь відреєструвати приймач мовлення?" ДУЖЕ! Капелюхи від того, хто поставив усі ці маленькі повідомлення, щоб допомогти нам у бійках.
Nerdy Bunz

1
Я зустрів це питання. коли я оновив targetSdkVersion до 28
illusionJJ

Відповіді:


574

Або

  • кешуйте об'єкт контексту за допомогою конструктора у вашому адаптері або
  • отримати це з вашого погляду.

Або в крайньому випадку,

  • додати - прапор FLAG_ACTIVITY_NEW_TASK до вашого наміру:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Редагувати - я б уникав встановлення прапорів, оскільки це буде заважати нормальному потоку стеку подій та історії.


6
Як щодо функції автопосилання TextView, коли я не можу керувати намірами (і таким чином прапорами), створеними системою?
Олексій Семенюк

75
Я отримую це виняток , коли я роблю що - щось на зразок цього context.startActivity(intent);я просто змінив contextвід ApplicationContextдо Activityтипу. Це вирішило проблему.
Суфіан

@AlexSemeniuk коли-небудь знайде рішення?

@AlexSemeniuk - autoLink працюватиме до тих пір, поки ви передасте активність як контекст адаптеру
Жорж

Я передав об’єкт контексту через конструктор, але його не працює. але FLAG_ACTIVITY_NEW_TASK для мене працює дуже добре, дякую.
Хірен

100

Ви можете досягти цього замість addFlagssetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Згідно з документацією, це:

Додайте додаткові прапори до наміру (або з наявним значенням прапорів).


EDIT

Будьте в курсі, якщо ви використовуєте прапори, які ви змінюєте стек історії, як йдеться у відповіді Алекса Волового :

... уникайте встановлення прапорів, оскільки це буде заважати нормальному потоку стеку подій та історії.


1
У мене дуже схожа проблема. У вас виникли якісь проблеми зі стеком історії чи чим-небудь іншим, як відповіді вище підказують?
Ейнар Сундгрен

1
Я не точно впевнений, що ви шукаєте, але ви можете розпочати діяльність без такої історії: Намір наміру = новий намір (Intent.ACTION_VIEW, "http: \\ www.google.com")); addFlags (Намір.FLAG_ACTIVITY_NO_HISTORY); startActivity (наміри);
Бруно Бієрі

Чому сюди не рекомендується додавати флаги? Наскільки критично перешкоджати нормальному потоку стеження подій та історії?
Джейсон Крс

@JasonKrs ви можете використовувати addFlags. Зауважте, що ви можете змінити стек історії залежно від доданого вами прапора. FLAG_ACTIVITY_NEW_TASK може бути використаний у цій ситуації. Докладніше читайте: developer.android.com/reference/android/content/…
Бруно Бієрі


40

Якщо ви отримали помилку через використання інструмента вибору create, як нижче:

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

Встановіть прапор, щоб створити такий вибір вибору:

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
Це було дуже корисно. Саме цей вибір повинен мати цей прапор!
Махді

2
Це правильне рішення, і саме те, що потрібно робити, new_task in intent.chooser
Рафаель

15

Крім того: якщо ви показуєте посилання у перегляді списку у фрагменті , не створюйте його таким

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

натомість дзвоніть

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

адаптер працює в обох випадках, але посилання працюють лише в останньому.


@ user2676468: це вирішило для мене проблему автопосилання.
Head Geek

Це має бути прийнятою відповіддю, а не використовувати прапори, це краще !!
Gastón Saillén

@ GastónSaillén, я не використовую getApplicationContext()(за винятком ініціалізації додатків), але переловив це виключення. Отже, ситуації можуть бути різними.
CoolMind

Це була моя проблема, я використовував getApplicationContext () для контексту. Визначення thisконтексту працює як те, що стосується поточної діяльності.
Брля

14

Я думаю, що, можливо, ви реалізуєте OnClickListener в неправильному місці - зазвичай вам слід обов’язково впровадити OnItemClickListener у своїй діяльності та встановити його на ListView, або у вас виникнуть проблеми зі своїми подіями ...


2
Ти ведеш мене до рішення. Мені потрібно було використовувати OnItemClickListener, призначений ListView. Ось декілька посилань для будь-кого іншого: developer.android.com/reference/android/widget/… androidpeople.com/… Дякую за допомогу.
Sako73

Будь ласка, надайте загальні відповіді. Відповідь Олексія Волового нижче вирішує проблему узагальнено.
devanshu_kaushik

Для нащадків: Якщо ви безпосередньо визначаєте його як setListener (новому слухачеві) для компонента потрібен контекст, ви створюєте неявну посилання на всю діяльність, яка просочить пам'ять, як ви б не вірили. Цього можна обійти, або стати статичним слухачем внутрішнього класу, або перемістивши слухача до окремого класу, якщо він повинен мати можливість обробляти вхідні дані з більш ніж одного походження.
G_V

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

або

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

змінити на нижче

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

8

На початку Android 28(Android P)активність

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

Тож найкращий спосіб - додавання 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);

Це потрібно для пристроїв 28 і вище.
Md

7

Дивіться, якщо ви створюєте намір у списку списків у якомусь методі

override onClick (View v).

тоді викличте контекст і через цей погляд:

v.getContext ()

Навіть не потрібно буде SetFlags ...


А яка була неправильна ситуація? v.getApplicationContext ()?
CoolMind

3

Для тих, хто отримує це на Xamarin.Android (MonoDroid), навіть коли StartActivity викликається від активності - це насправді помилка Xamarin з новим режимом виконання ART, див. Https://bugzilla.xamarin.com/show_bug.cgi?id=17630


Так, ви просто повинні зробити так, як було описано вище, але формулювання змінилося ... intent.SetFlags (ActivityFlags.NewTask);
Люк

3

Ще більше деталізуючи відповідь Олексія Волового -

у випадку, якщо ви отримаєте цю проблему з фрагментами, getActivity () працює добре, щоб отримати контекст

У інших випадках:

Якщо ви не хочете використовувати-

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

потім зробіть подібну функцію у своєму OutsideClass -

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

Тепер, у вашій основній діяльності, коли коли-небудь ви робите новий виклик OutsideClass вищезазначеним методом одразу після того, як ви визначите OutsideClass, даючи контекст діяльності як аргумент. Також у своїй основній діяльності зробіть функцію-

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

тепер поверніться до свого OutsideClass, і щоб розпочати нову діяльність, зробіть щось подібне -

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

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

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

Таким чином ви зможете розпочати різні дії, що викликаються з різних OutsideClass, не псуючи прапори.

Примітка. Постарайтеся не кешувати контекстний об’єкт через конструктор для фрагмента (з адаптером, його штрафом). У фрагменті повинен бути порожній конструктор, інакше програма збивається в деяких сценаріях.

не забудьте подзвонити

OutsideClass.gettingContext(Context context);

у функції onResume ().


3

Ця помилка виникає, коли зоряність не знає, яка його діяльність. Тому ви повинні додати активність перед startActivity ()

ви повинні встановити

context.startActivity(yourIntent);

Якщо ви телефонуєте startActivityз Fragment, абонент може часто бути фрагментом, а не діяльність.
CoolMind

2

На мій погляд, краще використовувати метод startActivity()просто у своєму коді Activity.class. Якщо ви використовуєте це в тому Adapterчи іншому класі, це призведе до цього.


2

У мене теж була така ж проблема. Перевірте весь контекст, який ви пройшли. Для " посилань " йому потрібен контекст діяльності, а не контекст програми .

Тут ви маєте перевірити:

1.) Якщо ви використовували LayoutInflater, тоді перевірте, який контекст ви пройшли.

2.) Якщо ви використовуєте будь-який адаптер, перевірте, який контекст ви пройшли.


2

У мене була така ж проблема. Проблема полягає в контексті. Якщо ви хочете відкрити будь-які посилання (наприклад, поділитися будь-яким посиланням через вибір), передайте контекст діяльності, а не контекст програми.

Не забудьте додати, myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)якщо ви не займаєтесь своєю діяльністю.


2

Використовуйте цей код у своїй Adapter_Activity та використовуйте context.startActivity(intent_Object)таintent_Object.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Подобається це:

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

Це працює....


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

Я сподіваюся, що це спрацює.


1

Зіштовхнувшись з тим же питанням, потім реалізували

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

і вирішили проблему.

Можливо, є ще одна причина, пов’язана з адаптером перегляду списку.
Ви можете побачити цей блог , описав його дуже добре.


корисний блог, Дякую :)
Rucha Bhatt Joshi

1

Використовуйте цей код. Добре працює для мене. Поділіться чимось із поза діяльності:

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

Налаштування прапорів зіпсує історію стеження
Ezio

1

Оскільки додавання прапорів впливає event_flowі stack_historyкраще передати "контекст програми" недіяльності, звідки потрібно викликати клас активності таким чином:

"ActivityClassName.this" (Хоча ви передаєте контекст таким чином, він буде містити всі деталі та інформацію, що вам потрібно викликати активність із сценарію бездіяльності)

Тому не потрібно встановлювати або додавати прапори, це спрацює нормально у кожному випадку.



0

Якщо ви посилаєтеся на розділ "Намір" у плагіні Кордова, встановлення прапора не допоможе. Замість цього використовуйте це -

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

0

Моя ситуація була дещо іншою, я тестую свій додаток, Espressoі мені довелося запустити свою діяльність з ActivityTestRuleінструментарію Context(який не є тим, хто надходить з Activity).

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

Мені довелося змінити прапори і додати orпобіжно ( |на Java) сIntent.FLAG_ACTIVITY_NEW_TASK

Отже, це призводить до:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.