我在我的 Android 应用程序中实现了一个 ListView
。我使用 ArrayAdapter
类的自定义子类绑定到此 ListView
。在被覆盖的 ArrayAdapter.getView(...)
方法中,我分配了一个 OnClickListener
。在 OnClickListener
的 onClick
方法中,我想启动一个新活动。我得到了例外:
Calling startActivity() from outside of an Activity context requires the
FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
如何获得 ListView
(当前的 Activity
)正在运行的 Context
?
任何一个
通过适配器中的构造函数缓存 Context 对象,或者
从你的角度得到它。
或者作为最后的手段,
在您的意图中添加 - FLAG_ACTIVITY_NEW_TASK 标志:
_
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
编辑 - 我会避免设置标志,因为它会干扰事件和历史堆栈的正常流动。
您可以使用 addFlags 而不是 setFlags
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
根据 documentation 它确实:
向意图添加其他标志(或使用现有标志值)。
编辑
当您使用标志时要小心,您可能会更改历史堆栈,如 Alex Volovoy's answer 所说:
...避免设置标志,因为它会干扰事件和历史堆栈的正常流动。
而不是使用 (getApplicationContext)
使用 YourActivity.this
activity.startActivity
而不是 context.startActivity
如果您因为使用如下创建选择器而出错:
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);
另外:如果您在片段中的列表视图中显示链接,请不要这样创建它
adapter = new ListAdapter(getActivity().getApplicationContext(),mStrings);
而是打电话
adapter = new ListAdapter(getActivity(),mStrings);
适配器在这两种情况下都可以正常工作,但链接仅在最后一种情况下有效。
getApplicationContext()
(应用程序初始化除外),但发现了这个异常。因此,情况可能会有所不同。
this
设置为上下文,因为它与当前活动相关。
我想也许你在错误的地方实现 OnClickListener - 通常你肯定应该在你的 Activity 中实现一个 OnItemClickListener 并将它设置在 ListView 上,否则你的事件会出现问题......
在 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);
CustomAdapter mAdapter = new CustomAdapter( getApplicationContext(), yourlist);
或者
Context mContext = getAppliactionContext();
CustomAdapter mAdapter = new CustomAdapter( mContext, yourlist);
改为下面
CustomAdapter mAdapter = new CustomAdapter( this, yourlist);
看,如果您正在以某种方法在侦听器中创建意图
override onClick (View v).
然后也通过这个视图调用上下文:
v.getContext ()
甚至不需要 SetFlags ...
对于在 Xamarin.Android (MonoDroid) 上获得此功能的任何人,即使 StartActivity 是从活动中调用的 - 这实际上是新 ART 运行时的 Xamarin 错误,请参阅https://bugzilla.xamarin.com/show_bug.cgi?id=17630
Xamarin.Essentials.Platform.CurrentActivity.StartActivity(intent);
详细阐述 Alex Volovoy 的答案 -
如果您遇到片段问题,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() 函数中也是如此。
当 startactivity 不知道哪个是他的活动时,就会出现此错误。所以你必须在 startActivity() 之前添加活动
你必须设置
context.startActivity(yourIntent);
Fragment
调用 startActivity
,则调用者通常可以是片段,而不是活动。
在我看来,最好在 Activity.class
的代码中使用 startActivity()
的方法。如果您在 Adapter
或其他类中使用它,它将导致该结果。
我也有同样的问题。检查您通过的所有上下文。对于“链接”,它需要活动上下文而不是应用程序上下文。
这是您应该检查的地方:
1.) 如果你使用了 LayoutInflater 然后检查你通过了什么上下文。
2.) 如果您使用任何适配器,请检查您通过了什么上下文。
我有同样的问题。问题在于上下文。如果您想打开任何链接(例如通过选择器共享任何链接)传递活动上下文,而不是应用程序上下文。
如果您不在活动中,请不要忘记添加 myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
。
在您的 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);
有用....
在您的 Activity(您在其中调用适配器)中,只需将 getActivityContext()
更改为 YourActivity.this
。这是一个例子:
yourAdapter = new YourAdapter(yourList, YourActivity.this); // Here YourActivity.this is the Context instead of getActivityContext()
recyclerView.setAdapter(yourAdapter);
Intent viewIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(viewIntent);
我希望这会奏效。
面临同样的问题然后实施
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
并解决了问题。
可能还有另一个与列表视图适配器有关的原因。
您可以看到This blog,描述得很好。
使用此代码。对我来说很好。从活动之外分享一些东西:
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);
由于添加标志会影响 event_flow
和 stack_history
,因此最好将“应用程序上下文”传递给您需要通过以下方式调用活动类的非活动:
“ActivityClassName.this”(当您以这种方式传递上下文时,它将包含您从非活动场景中调用活动所需的所有详细信息和信息)
所以不需要设置或添加标志,这在任何情况下都可以正常工作。
Intent i= new Intent(context, NextActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
如果您在 Cordova 插件中调用共享 Intent,设置标志将无济于事。而是使用这个 -
cordova.getActivity().startActivity(Intent.createChooser(shareIntent, "title"));
我的情况有点不同,我正在使用 Espresso
测试我的应用程序,我必须使用 ActivityTestRule
从仪器 Context
启动我的 Activity(这不是来自 Activity
的那个)。
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)
Kotlin 版本
val intent = Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this.startActivity(intent)
如果您使用数据绑定,只需获取您的上下文
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.Forms 或 Xamarin.Android 的人,在您的 Xamarin.Android 项目中,使用:
Xamarin.Essentials.Platform.CurrentActivity.StartActivity(intent);
请注意,这可能需要 Xamarin.Essentials v1.5 或更高版本
正如@Alex Volovoy 提到的,应该避免设置标志,因为它会干扰事件和历史堆栈的正常流动。
context.startActivity(intent);
的操作时遇到此异常,我只是将context
从ApplicationContext
更改为Activity
类型。这解决了问题。