ChatGPT解决这个技术问题 Extra ChatGPT

从 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

我认为亚历克斯的答案应该是您问题的“公认”解决方案,因为它以更通用的方式纠正了您提到的错误
我喜欢“这真的是你想要的吗?” ...我之前收到一条消息说“你确定你没有忘记在某处取消注册广播接收器吗?”惊人的!向那些把所有这些小信息放进去帮助我们的人脱帽致敬。
我遇到了这个问题。当我将 targetSdkVersion 更新为 28 时。

L
LarsH

任何一个

通过适配器中的构造函数缓存 Context 对象,或者

从你的角度得到它。

或者作为最后的手段,

在您的意图中添加 - FLAG_ACTIVITY_NEW_TASK 标志:

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

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


我无法控制系统创建的 Intent(以及标志)的 TextView 的 autoLink 功能呢?
我在执行类似 context.startActivity(intent); 的操作时遇到此异常,我只是将 contextApplicationContext 更改为 Activity 类型。这解决了问题。
@AlexSemeniuk 有没有找到解决方案?
@AlexSemeniuk - 只要您将活动作为上下文传递给适配器,自动链接就会起作用
我通过构造函数传递了 Context 对象,但它不起作用。但 FLAG_ACTIVITY_NEW_TASK 对我来说效果很好,谢谢。
B
Bruno Bieri

您可以使用 addFlags 而不是 setFlags

myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

根据 documentation 它确实:

向意图添加其他标志(或使用现有标志值)。

编辑

当您使用标志时要小心,您可能会更改历史堆栈,如 Alex Volovoy's answer 所说:

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


我有一个非常相似的问题。您是否遇到过历史堆栈或上述答案所暗示的任何其他问题?
我不确定您在寻找什么,但您可以在没有类似历史记录的情况下启动活动:Intent intent = new Intent(Intent.ACTION_VIEW, "http:\\www.google.com"));intent. addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);开始活动(意图);
为什么不建议在这里添加标志?干扰事件和历史堆栈的正常流动有多重要?
@JasonKrs 你可以使用 addFlags。请注意,您可以根据添加的标志更改历史堆栈。在这种情况下可以使用 FLAG_ACTIVITY_NEW_TASK。有关详细信息,请阅读:developer.android.com/reference/android/content/…
J
Jeffrey Nyauke

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


这对我有用,即使用 activity.startActivity 而不是 context.startActivity
最好的答案!
这帮助我弄清楚了我的问题。我的代码最终看起来像这样:`context.currentActivity?.let { /* do things with context */ }
s
sanath_p

如果您因为使用如下创建选择器而出错:

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.chooser 中的 new_task
这是唯一对我有用的解决方案。
O
Olcay Ertaş

另外:如果您在片段中的列表视图中显示链接,请不要这样创建它

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

而是打电话

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

适配器在这两种情况下都可以正常工作,但链接仅在最后一种情况下有效。


@user2676468:这为我解决了自动链接问题。
这应该是一个公认的答案,而不是使用标志,这更好!
@GastónSaillén,我不使用 getApplicationContext() (应用程序初始化除外),但发现了这个异常。因此,情况可能会有所不同。
这是我的问题,我使用 getApplicationContext() 作为上下文。将 this 设置为上下文,因为它与当前活动相关。
m
mreichelt

我想也许你在错误的地方实现 OnClickListener - 通常你肯定应该在你的 Activity 中实现一个 OnItemClickListener 并将它设置在 ListView 上,否则你的事件会出现问题......


你引导我找到解决方案。我需要使用分配给 ListView 的 OnItemClickListener。以下是其他人的一些链接:developer.android.com/reference/android/widget/… androidpeople.com/… 感谢您的帮助。
请提供通用答案。 Alex Volovoy 下面的回答以一种通用的方式解决了这个问题。
对于后代:如果您在需要上下文的组件上直接将其定义为 setListener(new Listener),则您会创建对整个活动的隐式引用,这会像您不相信的那样泄漏内存。如果它需要能够处理来自多个来源的输入,则可以通过制作静态内部类侦听器或将侦听器移动到单独的类来规避这一点。
A
Alen Lee

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

这是 28 及以上设备所必需的。
O
Olcay Ertaş
CustomAdapter mAdapter = new CustomAdapter( getApplicationContext(), yourlist);

或者

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

改为下面

CustomAdapter mAdapter = new CustomAdapter( this, yourlist);

s
slfan

看,如果您正在以某种方法在侦听器中创建意图

override onClick (View v).

然后也通过这个视图调用上下文:

v.getContext ()

甚至不需要 SetFlags ...


什么是错误的情况? v.getApplicationContext()?
r
rouen

对于在 Xamarin.Android (MonoDroid) 上获得此功能的任何人,即使 StartActivity 是从活动中调用的 - 这实际上是新 ART 运行时的 Xamarin 错误,请参阅https://bugzilla.xamarin.com/show_bug.cgi?id=17630


是的,您只需要按照上面的描述进行操作,但是措辞已经改变... intent.SetFlags(ActivityFlags.NewTask);
意图意图 = new Intent();意图.AddFlags(ActivityFlags.NewTask); intent.SetData(Android.Net.Uri.Parse(baseUrl + @"name_of_apk")); Android.App.Application.Context.StartActivity(intent);
无需在 Xamarin.Android 中使用 SetFlags。使用Xamarin.Essentials.Platform.CurrentActivity.StartActivity(intent);
F
Flying Monkey

详细阐述 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() 函数中也是如此。


C
Cabezas

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

你必须设置

context.startActivity(yourIntent);

如果您从 Fragment 调用 startActivity,则调用者通常可以是片段,而不是活动。
r
rayryeng

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


c
codemaniac

我也有同样的问题。检查您通过的所有上下文。对于“链接”,它需要活动上下文而不是应用程序上下文。

这是您应该检查的地方:

1.) 如果你使用了 LayoutInflater 然后检查你通过了什么上下文。

2.) 如果您使用任何适配器,请检查您通过了什么上下文。


O
Ori Lentz

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

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


O
Olcay Ertaş

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

有用....


F
Félix Maroy

在您的 Activity(您在其中调用适配器)中,只需将 getActivityContext() 更改为 YourActivity.this。这是一个例子:

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

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

我希望这会奏效。


O
Olcay Ertaş

面临同样的问题然后实施

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

并解决了问题。

可能还有另一个与列表视图适配器有关的原因。
您可以看到This blog,描述得很好。


有用的博客,谢谢。 :)
O
Olcay Ertaş

使用此代码。对我来说很好。从活动之外分享一些东西:

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

设置标志会弄乱堆栈跟踪历史记录
O
Olcay Ertaş

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

“ActivityClassName.this”(当您以这种方式传递上下文时,它将包含您从非活动场景中调用活动所需的所有详细信息和信息)

所以不需要设置或添加标志,这在任何情况下都可以正常工作。


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

S
Sandeep Kumar

如果您在 Cordova 插件中调用共享 Intent,设置标志将无济于事。而是使用这个 -

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

O
Olcay Ertaş

我的情况有点不同,我正在使用 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)

C
Community

Kotlin 版本

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

k
kuzdu

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

binding.root.context

这解决了我的问题。


K
Kumar Santanu

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

谢谢你。


J
Junaid Pathan

对于来自 Xamarin.Forms 或 Xamarin.Android 的人,在您的 Xamarin.Android 项目中,使用:

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

请注意,这可能需要 Xamarin.Essentials v1.5 或更高版本

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