Вызов startActivity () вне контекста Activity


368

Я реализовал 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
Я люблю это "Это действительно то, что вы хотите?" ... До этого у меня было сообщение: "Вы уверены, что не забыли где-нибудь отменить регистрацию радиоприемника?" КЛАССНО! Снимаю шляпу перед тем, кто вложил все эти маленькие сообщения, чтобы помочь нам сквакам.
Всезнайка Бунц

1
Я встретил эту проблему. когда я обновил targetSdkVersion до 28.
illusionJJ

Ответы:


576

Или

  • кэшируйте объект Context через конструктор в вашем адаптере, или
  • получите это от вашего взгляда.

Или, в крайнем случае,

  • добавьте - FLAG_ACTIVITY_NEW_TASK пометить ваше намерение:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Редактировать - я бы избегал установки флагов, так как это будет мешать нормальному потоку событий и стека истории.


6
Как насчет функции автоссылки TextView, где я не могу контролировать намерения (и, следовательно, флаги), созданные системой?
Алекс Семенюк

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

@AlexSemeniuk когда-нибудь найти решение?

@AlexSemeniuk - автоссылка будет работать до тех пор, пока вы передаете действие в качестве контекста адаптеру
Жорж

Я передал объект Context через конструктор, но он не работает. но FLAG_ACTIVITY_NEW_TASK работает очень хорошо для меня, спасибо.
Хирен

100

Вы можете достичь этого с помощью addFlags вместоsetFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Согласно документации это делает:

Добавьте дополнительные флаги к цели (или с существующим значением флагов).


РЕДАКТИРОВАТЬ

Помните, что если вы используете флаги, вы меняете стек истории, поскольку ответ Алексея Волового гласит:

... избегайте установки флагов, так как это будет мешать нормальному потоку событий и стека истории.


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

1
Я не совсем уверен, что вы ищете, но вы можете начать занятие без такой истории: Intent intent = new Intent (Intent.ACTION_VIEW, "http: \\ www.google.com")); намерение. addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity (намерение);
Бруно Биери

Почему не рекомендуется добавлять сюда флаги? Насколько критично вмешиваться в нормальный поток событий и стек истории?
Джейсон Krs

@JasonKrs вы можете использовать addFlags. Просто знайте, что вы можете изменить стек истории в зависимости от добавляемого вами флага. FLAG_ACTIVITY_NEW_TASK может использоваться в этой ситуации. Для более подробной информации читайте: developer.android.com/reference/android/content/…
Бруно Биери


40

Если вы получили ошибку из-за использования create chooser, как показано ниже:

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

Установите флаг для создания chooser следующим образом:

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 в intent.chooser
Рафаэль Гимарайнш

15

Кроме того: если вы показываете ссылки в списке в фрагменте , не создавайте его так

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

вместо вызова

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

В обоих случаях адаптер работает нормально, но ссылки работают только в последнем.


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

Это должен быть принятый ответ, вместо использования флагов это лучше !!
Гастон Сайлен

@ GastónSaillén, я не использую getApplicationContext()(кроме инициализации приложения), но поймал это исключение. Итак, ситуации могут быть разными.
CoolMind

Это была моя проблема, я использовал getApplicationContext () для контекста. Установка в thisкачестве контекста работает так, как она связана с текущей деятельностью.
Brlja

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 Mohsin

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

затем сделайте такую ​​функцию в вашем внешнем классе -

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

Теперь вернитесь в свой Внешний класс и, чтобы начать новое занятие, сделайте что-то вроде этого:

@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

У меня такая же проблема. Проблема с контекстом. Если вы хотите открыть какие-либо ссылки (например, поделиться какой-либо ссылкой через chooser), передайте контекст активности, а не контекст приложения.

Не забудьте добавить, 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);

Настройка флагов испортила историю трассировки стека
Эцио

1

Поскольку добавление флагов влияет, event_flowи stack_historyлучше передать «контекст приложения» в неактивность, откуда вам нужно вызывать класс активности следующим образом:

«ActivityClassName.this» (если вы передадите контекст таким образом, он будет содержать все детали и информацию, необходимые для вызова действия из сценария бездействия)

Таким образом, нет необходимости устанавливать или добавлять флаги, это будет работать нормально в каждом случае.



0

Если вы запускаете плагин Intent в Cordova, установка флага не поможет. Вместо этого используйте это -

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.