【问题标题】:Calling startActivity() from outside of an Activity context从 Activity 上下文之外调用 startActivity()
【发布时间】:2011-04-24 12:40:45
【问题描述】:

我在我的 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 时。

标签: android android-activity android-context


【解决方案1】:

要么

  • 通过适配器中的构造函数缓存 Context 对象,或者
  • 从你的视野中得到它。

或者作为最后的手段,

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

_

myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

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

【讨论】:

  • TextView 的 autoLink 功能在我无法控制系统创建的 Intent(以及由此产生的标志)的情况下怎么样?
  • 当我在做这样的事情时遇到了这个异常context.startActivity(intent); 我只是将contextApplicationContext 更改为Activity 类型。这解决了问题。
  • @AlexSemeniuk 找到解决方案了吗?
  • @AlexSemeniuk - 只要您将活动作为上下文传递给适配器,自动链接就会起作用
  • 我通过构造函数传递了 Context 对象,但它不起作用。但 FLAG_ACTIVITY_NEW_TASK 对我来说效果很好,谢谢。
【解决方案2】:

您可以使用 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);开始活动(意图);
  • 为什么这里不推荐addFlags?干扰事件和历史堆栈的正常流动有多重要?
  • @JasonKrs 你可以使用 addFlags。请注意,您可以根据添加的标志更改历史堆栈。在这种情况下可以使用 FLAG_ACTIVITY_NEW_TASK。更多详情请阅读:developer.android.com/reference/android/content/…
【解决方案3】:

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

【讨论】:

  • 这对我有用,即使用activity.startActivity 而不是context.startActivity
  • 最佳答案!
  • 这帮助我找出了我的问题。我的代码最终看起来像这样:`context.currentActivity?.let { /* do things with context */ }
【解决方案4】:

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

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
  • 这是唯一对我有用的解决方案。
【解决方案5】:

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

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

改为调用

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

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

【讨论】:

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

我认为您可能在错误的位置实现 OnClickListener - 通常您绝对应该在 Activity 中实现 OnItemClickListener 并将其设置在 ListView 上,否则您的事件会出现问题...

【讨论】:

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

    看看,如果你用某种方法在监听器中创建意图

    override onClick (View v).
    

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

    v.getContext ()
    

    甚至不需要 SetFlags ...

    【讨论】:

    • 出了什么问题? v.getApplicationContext()?
    【解决方案10】:

    对于在 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);
    【解决方案11】:

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

    【讨论】:

      【解决方案12】:

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

      你必须设置

      context.startActivity(yourIntent);
      

      【讨论】:

      • 如果你从Fragment调用startActivity,调用者通常可以是一个片段,而不是一个活动。
      【解决方案13】:

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

      【讨论】:

        【解决方案14】:

        我也遇到了同样的问题。检查您通过的所有上下文。对于“links”,它需要 Activity Context 而不是 Application context

        这是你应该检查的地方:

        1.) 如果您使用了 LayoutInflater,请检查您通过了什么上下文。

        2.) 如果您使用任何 Adapter,请检查您已通过的上下文。

        【讨论】:

          【解决方案15】:

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

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

          【讨论】:

            【解决方案16】:

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

            它有效....

            【讨论】:

              【解决方案17】:
              Intent viewIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);    
              viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);    
              startActivity(viewIntent);   
              

              我希望这会奏效。

              【讨论】:

                【解决方案18】:

                遇到同样的问题,然后实施

                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                

                问题解决了。

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

                【讨论】:

                • 有用的博客,谢谢。 :)
                【解决方案19】:

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

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

                【讨论】:

                • 设置标志会破坏堆栈跟踪历史
                【解决方案20】:

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

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

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

                【讨论】:

                  【解决方案21】:

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

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

                  【讨论】:

                    【解决方案22】:
                    Intent i= new Intent(context, NextActivity.class);
                    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                    

                    【讨论】:

                      【解决方案23】:

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

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

                      【讨论】:

                        【解决方案24】:

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

                        【讨论】:

                          【解决方案25】:

                          Kotlin 版本

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

                          【讨论】:

                            【解决方案26】:

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

                            binding.root.context
                            

                            这解决了我的问题。

                            【讨论】:

                              【解决方案27】:

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

                              谢谢。

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 2019-07-17
                                • 2011-04-11
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2018-06-20
                                相关资源
                                最近更新 更多