Android 未调用 onNewIntent

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23446120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:10:06  来源:igfitidea点击:

onNewIntent is not called

androidandroid-intent

提问by Moritz

I have very strange situation.
Having one app, I decided to create another one from the code of first one.
I copied .xml files, copied .java files so that everything is OK.
But there's one HUGE problem: my onNewIntent(Intent intent)method is called in first project, but it's not called in the second project (the code is the same!)

Method, which could trigger then, but can't trigger now

我有很奇怪的情况。
有了一个应用程序,我决定根据第一个应用程序的代码创建另一个应用程序。
我复制了 .xml 文件,复制了 .java 文件,以便一切正常。
但是有一个巨大的问题:我的onNewIntent(Intent intent)方法在第一个项目中被调用,但在第二个项目中没有调用(代码是一样的!)

方法,当时可以触发,但现在不能触发

public void onClick(View arg0) {
    Intent browserInt = new Intent (Intent.ACTION_VIEW, 
    Uri.parse("https://oauth.yandex.ru/authorize?response_type=token&client_id=zzzzz"));
    browserInt.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(browserInt);
}

Here's onNewIntent() method:

这是 onNewIntent() 方法:

@Override
protected void onNewIntent(Intent intent){
    System.out.println(" I WORKED!");
    Uri uri = intent.getData();
    if (uri!=null) {
        String m = uri.toString().split("#")[1];
        String[] args = m.split("&");
        String arg = args[0];
        String token = arg.split("=")[1];
        System.out.println(token);
    }   
}

I don't see "I WORKED" in my logs, unfortunately.
I've read lots of similar questions both on SO and over the Internet, tried setting Intent flags SINGLE_TOP, SINGLE_TASK and so on.

不幸的是,我在日志中没有看到“我工作过”。
我在 SO 和 Internet 上阅读了很多类似的问题,尝试设置 Intent 标志 SINGLE_TOP、SINGLE_TASK 等。

Here's the Android Manifest of WORKING project:

这是 WORKING 项目的 Android 清单:

<application 
    android:name="yyy"
    android:icon="@drawable/yaru_icon"
    android:allowBackup="false"
    android:label="xxx"
    android:theme="@style/LightTheme">

    <activity
        android:name=".Main"
        android:label="xxx"
        android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
</application>

I'm quite desperate, why the similar code is not working anymore?

我很绝望,为什么类似的代码不再起作用了?

EDIT:I've tried everything: SINGLE_TOP, SINGLE_INSTANCE, SINGLE_TASK..
but then I occasionally did this on another activity:

编辑:我已经尝试了一切:SINGLE_TOP、SINGLE_INSTANCE、SINGLE_TASK ..
但后来我偶尔会在另一个活动中这样做:

Main m = new Main();
m.onNewIntent(this.getIntent());

And it finally worked!
I don't know, whether it's a dirty workaround or a bug, if anyone can explain it, please, comment.

它终于奏效了!
我不知道,这是一个肮脏的解决方法还是一个错误,如果有人可以解释它,请发表评论。

回答by Moritz

PREAMBLE:

前言:

Allright, I'm a little late to this one, but as I stumbled over the same issue and no answer here or for any of the other four stackoverflow questions, I found for this issue, solved the problem for me, here's what I figured out.

好吧,我对这个问题有点晚了,但是当我偶然发现同样的问题并且在这里或其他四个 stackoverflow 问题中的任何一个都没有答案时,我找到了这个问题,为我解决了这个问题,这就是我的想法出去。

ANSWER:

回答:

There are several possible reasons, why onNewIntent isn't called and I'm gonna list them all - well all of which I know.

有几个可能的原因,为什么没有调用 onNewIntent,我将列出所有这些 - 我知道所有这些。

  1. As mentioned in many answers before and in the doc for the onNewIntent function (link in Yaroslavs answer), you either need the android:launchMode="singleTop"manifest entry for the activity, where you want onNewIntent to be called, or the Intent used for starting the activity must have the flag FLAG_ACTIVITY_SINGLE_TOP. You don't need both (it's a |aka. logical ornot a &aka. logical and)! onNewIntent should also be called for android:launchMode="singleTask", but before you use that, you better check out the android:launchMode documentation, because it has much more consequences, than just one function call.
  2. In older versions of Android there was a bug, which basically prevented android:launchMode="singleTop"from working as specified and thus onNewIntent from being called. The bug was never officially solved, but I couldn't reproduce it in version 4.4.2 (Samsung S4 Mini). So it seems to have been fixed at some point between 4.0.x and 4.4.2.
  3. Not every time the preconditions as mentioned before are fulfilled, onNewIntent will be called. As the documentation of the function states:

    ...when the activity is re-launched while at the top of the activity stack instead of a new instance of the activity being started, onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it."

    That means, if the activity is newly created, onNewIntent won't be called, no matter what launchMode or Intent flags you did set!

    • To my understanding, either onCreate or onNewIntent is called, but never both.
    • So, if you wanna pass data to the activity through the Intent and it should always work (as in my case), no matter if the activity is relaunched or the activity is freshly created, you can do as described in this very useful blog post.
    • As a variation of the solution described in the above blog post, you could also take advantage of the fact, that no matter if onNewIntent or onCreate was called, onResume will always be called afterwards, and do something like this:

      @Override
      protected void onNewIntent(Intent intent) {
          super.onNewIntent(intent);
          setIntent(intent);
      }
      
      @Override
      protected void onResume() {
          super.onResume();
          Intent intent = getIntent();
          // ... do what you wanna do with the intent
      }
      

      For this example getIntent will always get you the Intent you used for the startActivity call or the Notification, as the new Intent will also be set for the Activity, if the Activity is freshly created (and thus onCreate was called).

  1. 正如之前和 onNewIntent 函数的文档中提到的许多答案(Yaroslavs 答案中的链接),您需要活动的android:launchMode="singleTop"清单条目,您希望在其中调用 onNewIntent,或者用于启动活动的 Intent 必须具有标志FLAG_ACTIVITY_SINGLE_TOP。你不需要两者(它|又名。逻辑or而不是&又名。逻辑and)!onNewIntent 也应该被调用android:launchMode="singleTask",但是在你使用它之前,你最好查看 android:launchMode 文档,因为它有更多的后果,而不仅仅是一个函数调用。
  2. 在旧版本的 Android 中有一个错误,它基本上阻止android:launchMode="singleTop"了按规定工作,因此无法调用 onNewIntent。该错误从未正式解决,但我无法在版本 4.4.2(Samsung S4 Mini)中重现它。所以它似乎已经在 4.0.x 和 4.4.2 之间的某个时间点得到修复。
  3. 并非每次满足前面提到的先决条件时,都会调用 onNewIntent。正如该函数的文档所述:

    ...当活动在活动堆栈的顶部重新启动而不是启动活动的新实例时,将在现有实例上调用 onNewIntent() 并使用用于重新启动它的 Intent .

    这意味着,如果活动是新创建的,则不会调用 onNewIntent,无论您设置了什么 launchMode 或 Intent 标志!

    • 据我了解,onCreate 或 onNewIntent 都被调用,但永远不会同时调用。
    • 因此,如果您想通过 Intent 将数据传递给 Activity 并且它应该始终有效(就像我的情况一样),无论是重新启动 Activity 还是新创建的 Activity,您都可以按照这篇非常有用的博客文章中的描述进行操作.
    • 作为上述博客文章中描述的解决方案的变体,您还可以利用这样一个事实,即无论是 onNewIntent 还是 onCreate 被调用,onResume 都将在之后被调用,并执行如下操作:

      @Override
      protected void onNewIntent(Intent intent) {
          super.onNewIntent(intent);
          setIntent(intent);
      }
      
      @Override
      protected void onResume() {
          super.onResume();
          Intent intent = getIntent();
          // ... do what you wanna do with the intent
      }
      

      对于此示例,getIntent 将始终为您提供用于 startActivity 调用或通知的 Intent,因为如果 Activity 是新创建的(因此调用了 onCreate),也将为该 Activity 设置新的 Intent。

POSTAMBLE:

后文:

Sorry for the long post. I hope you found something useful in it.

抱歉,帖子太长了。我希望你能从中找到有用的东西。

回答by Yaroslav Mytkalyk

The Activity you want to receive onNewIntent() in should have

您想要接收 onNewIntent() 的 Activity 应该有

android:launchMode="singleTop"

Or add the flag tn intent

或添加标志 tn 意图

browserInt.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
                    Intent.FLAG_ACTIVITY_SINGLE_TOP);

As documented in onNewIntent(Intent)

onNewIntent(Intent) 中所述

回答by Nate Cook

Here's one situation that might bite you, along with a bit more information: onNewIntentis called as expected with this code:

这是一种可能会让您感到困扰的情况,以及更多信息:onNewIntent使用以下代码按预期调用:

Intent intent = new Intent...
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
finish();
startActivity(intent);

but not with this code

但不是用这个代码

Intent intent = new Intent...
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
finish();

The reason for that is that, in the second code block, the new activity is added on top before calling finish for the current activity, so to get the second code block to work you must add the FLAG_ACTIVITY_CLEAR_TOPflag as suggested by some of the other answers, like this:

原因是,在第二个代码块中,在为当前活动调用完成之前将新活动添加到顶部,因此要使第二个代码块工作,您必须FLAG_ACTIVITY_CLEAR_TOP按照其他一些答案的建议添加标志, 像这样:

Intent intent = new Intent...
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

Note that finishis not called at all here, because it is called for you. From the documentation for the FLAG_ACTIVITY_CLEAR_TOP flag:

请注意,finish这里根本没有调用它,因为它是为您调用的。从FLAG_ACTIVITY_CLEAR_TOP 标志文档中

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.

如果设置,并且正在启动的活动已经在当前任务中运行,那么它不会启动该活动的新实例,而是将关闭它之上的所有其他活动,并且此 Intent 将被传递到(现在在顶部)旧活动作为新意图。

回答by Yajur Sehgal

I was using onNewIntentfor search implementation in Android. I came across the problem that onNewIntentwasn't being called when I used the Go button on the keyboard in the emulator. I solved the issue by placing my code for handling the intent in the onCreatemethod also. This needs to be done to make sure that the intent action is handled when a fresh instance of the activity is started.

onNewIntent在 Android 中用于搜索实现。onNewIntent当我在模拟器中使用键盘上的 Go 按钮时,我遇到了没有被调用的问题。我也通过在方法中放置处理意图的代码解决了这个问题onCreate。需要这样做以确保在启动活动的新实例时处理意图操作。

This posed a problem as onCreateis called whenever the activity is restored from a previous state too. So, the intent handling method gets called even when an orientation change occurs.

这带来了一个问题,onCreate每当活动从以前的状态恢复时就会被调用。因此,即使发生方向更改,也会调用意图处理方法。

Solution : Use if (savedInstanceState==null)to determine if activity is being restored from a previous state, or is it a fresh search.

解决方案:if (savedInstanceState==null)用于确定活动是从以前的状态恢复,还是重新搜索。

回答by prodaea

The best way to handle onNewIntentwith singleTopis simply this:

处理的最佳方式onNewIntentsingleTop很简单:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
}

Then do all of your logic on getIntentinside onResume.

然后在getIntentinside上执行所有逻辑onResume

回答by Armando Esparza García

To enter to the onNewIntent method, you need in your AndroidManifest.xml file, put after set you main activity a launch mode, in this launch mode you have to put singleInstance e.g:

要进入 onNewIntent 方法,您需要在您的 AndroidManifest.xml 文件中,在设置您的主要活动之后放置一个启动模式,在此启动模式中您必须放置 singleInstance 例如:

<activity 
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleInstance"
        android:windowSoftInputMode="adjustPan" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

Now you will able to enter to you onNewIntent method.

现在您将能够输入您的 onNewIntent 方法。