从Activity上下文外部调用startActivity()

我已经在我的Android应用程序中实现了ListView。我使用ArrayAdapter类的自定义子类绑定到这个ListView。在被重写的ArrayAdapter.getView(...)方法中,我分配了一个OnClickListener。在OnClickListeneronClick方法中,我想启动一个新活动。我得到了一个异常:

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

如何获得ListView(当前的Activity)正在工作的Context ?

325733 次浏览

我认为也许你在错误的地方实现OnClickListener -通常你应该在你的活动中实现OnItemClickListener,并将其设置在ListView上,否则你会遇到事件问题…

要么

  • 通过适配器中的构造函数缓存Context对象,或者
  • 把它从你的视图中取出来。

或者作为最后的手段,

  • 添加FLAG_ACTIVITY_NEW_TASK标志到你的意图:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

编辑-我将避免设置标志,因为它将干扰正常的事件和历史堆栈流。

你可以用addFlags .代替setFlags来实现它

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

根据文档,它做:

添加额外的标志到意图(或与现有的标志值)。


编辑

当你使用可能改变历史堆栈的标志时要小心,就像Alex Volovoy的回答说的那样:

...避免设置标志,因为它会干扰正常的事件和历史堆栈流。

对于任何在Xamarin的。Android (MonoDroid)上得到这个的人,即使从activity调用StartActivity -这实际上是Xamarin bug与新的ART运行时,请参阅https://bugzilla.xamarin.com/show_bug.cgi?id=17630

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

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

更改如下

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

在我看来,最好只在Activity.class的代码中使用startActivity()的方法。如果你在Adapter或其他类中使用它,它将导致。

另外:如果你在片段的listview中显示链接,不要这样创建它

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

而不是打电话

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

适配器在这两种情况下都工作得很好,但链接只在最后一种情况下工作。

当startactivity不知道哪个是他的activity时,就会出现这个错误。所以你必须在startActivity()之前添加activity

你必须设置

context.startActivity(yourIntent);

再详细阐述一下Alex Volovoy的回答

如果你在使用片段时遇到这个问题,getActivity()可以很好地获取上下文

其他情况:

如果你不想用-

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

然后在你的outeclass -中创建一个这样的函数

public void gettingContext(Context context){
real_context = context;//where real_context is a global variable of type Context
}
现在,在你的主活动中,当你创建一个新的outside eclass时,在你定义了给出活动上下文作为参数的outside eclass之后,立即调用上面的方法。 在主活动中创建一个函数-

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

现在回到你的outeclass,并开始一个新的活动,像这样做-

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


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


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

通过这种方式,您将能够从不同的outside eclass启动不同的活动,而不会弄乱标志。

注意-尽量不要通过构造函数缓存上下文对象的片段(与适配器,它的好)。一个片段应该有一个空的构造函数,否则应用程序在某些情况下崩溃。

记得打电话

OutsideClass.gettingContext(Context context);

在onResume()函数中也一样。

我也有同样的问题。检查您传递的所有上下文。对于'链接',它需要活动背景而不是应用程序上下文

以下是你应该检查的地方:

1)。如果使用LayoutInflater,则检查所传递的上下文。

2)。如果你正在使用任何适配器,检查你传递了什么上下文。

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

我希望这能奏效。

我也有同样的问题。问题在于环境。如果您想打开任何链接(例如通过选择器共享任何链接),则传递活动上下文,而不是应用程序上下文。

如果你不在你的活动中,不要忘记添加myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

看,如果你在某个方法的监听器中创建一个意图

override onClick (View v).

然后通过这个视图调用context:

v.getContext ()

甚至不需要SetFlags…

不要使用(getApplicationContext),而是使用YourActivity.this

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

如果你因为使用创建选择器而出错,如下所示:

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

面对同样的问题,然后实施

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

解决了这个问题。

可能还有另一个原因与列表视图适配器有关 你可以看到这个博客,描述得很好

使用这段代码。对我来说没问题。分享活动之外的东西:

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

如果你在Cordova插件中调用共享意图,设置标志将不起作用。而是用这个——

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

我的情况有点不同,我使用Espresso测试我的应用程序,我必须从仪表Context(这不是一个来自Activity)启动我的活动与ActivityTestRule

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

我不得不改变标志,并在Intent.FLAG_ACTIVITY_NEW_TASK中按位添加or (Java中的|)

结果是:

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

由于添加标志会影响event_flowstack_history,因此最好将“应用程序上下文”传递给非活动,从那里您需要以以下方式调用活动类:

“ActivityClassName。(当你以这种方式传递上下文时,它将包含你从非活动场景中调用一个活动所需的所有细节和信息)

所以不需要设置或添加标志,这将在任何情况下工作良好。

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

它的工作原理……

芬兰湾的科特林版本

val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)

Android 28(Android P) startActivity

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

在你的Activity中(你调用适配器的地方),只需要用YourActivity.this改变getActivityContext()。 下面是一个例子:

yourAdapter = new YourAdapter(yourList, YourActivity.this); // Here YourActivity.this is the Context instead of getActivityContext()
recyclerView.setAdapter(yourAdapter);

如果使用数据绑定,只需获取上下文

binding.root.context

这解决了我的问题。

从视图的Activity上下文外部调用startActivity()

val context = activity.applicationContext
openBrowser(context, MenuUrl.TERM_CONDITION)

   1. val context = binding.root.context // If you are using view binding
2. val context = yourView.context // If you are not use view binding
openBrowser(context, MenuUrl.TERM_CONDITION)

谢谢你!

对于来自Xamarin的。形式Xamarin的。安卓的人,在你的Xamarin。Android项目,使用:

Xamarin.Essentials.Platform.CurrentActivity.StartActivity(intent);

请注意,这可能需要Xamarin。Essentials v1.5或以上版本

正如@Alex Volovoy所提到的,应该避免设置标志,因为它会干扰事件和历史堆栈的正常流程。