onNewIntent is not called

2020-01-29 04:48发布

问题:

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

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:

@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.

Here's the Android Manifest of WORKING project:

<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:

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.

回答1:

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.

ANSWER:

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

  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 or not 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).

POSTAMBLE:

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



回答2:

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

android:launchMode="singleTop"

Or add the flag tn intent

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

As documented in onNewIntent(Intent)



回答3:

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

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_TOP flag as suggested by some of the other answers, like this:

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

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

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.



回答4:

I was using onNewIntent for search implementation in Android. I came across the problem that onNewIntent wasn'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 onCreate method also. This needs to be done to make sure that the intent action is handled when a fresh instance of the activity is started.

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

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



回答5:

The best way to handle onNewIntent with singleTop is simply this:

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

Then do all of your logic on getIntent inside onResume.



回答6:

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:

<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.