How we can use onNewIntent() in any Activity? - android

What is the real use of onNewIntent() in the activity life cycle and how do we use this method?

This is called for activities that set launchMode to "singleTop" in their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent).
If you set to single top, the activity will not be launched if it is already running at the top of the history stack. It will not relaunch just show from stack.

Check this link onNewIntent()
In manifest.xml, in an activity tag set launchmode="singleTask"

Above answers are incomplete.
In case the activity 'a1' of Application 'A1' has launch mode "singleTask" or "singleTop" and is already alive (in task t1) but paused, and now another task (say Task t2) (usually another android app) sends an intent to activity a1 of application A1, then instead of creating another instance of activity in task t2, android resumes a1 from task t1, by issuing a callback to onNewIntent(intent) method in a1.
Tasks and back stack is an important concept, no blog explains better than android documentation itself.

Related

Starting Activity from Service Context

I want to start an activity from service context. But I am bound to use flag = Intent.FLAG_ACTIVITY_NEW_TASK which is creating multiple instance of the activity since it is throwing Run-Time-Exception with other flags.
How can we launch an activity from service so that multi instances of activity will not be created, if already activity in recent tasks it will launch that only??
You can combine different flags, like 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.
...
This launch mode can also be used to good effect in conjunction with FLAG_ACTIVITY_NEW_TASK: if used to start the root activity of a task, it will bring any currently running instance of that task to the foreground, and then clear it to its root state. This is especially useful, for example, when launching an activity from the notification manager.
and FLAG_ACTIVITY_CLEAR_TASK
If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK.
with FLAG_ACTIVITY_NEW_TASK. Which one to use depends on what exactly do you want to achieve.
Check the documentation of the flags in the Intent class and Tasks and Back Stack.

How do I avoid returning to a parent activity performing a background task before finishing itself?

My app has a launcher activity that looks at the intent used to call it and calls one of many activities based on the intent (let's call the child activity B). The launcher activity also launches an AsyncTask to do some clean up in SharedPreferences in the background. Once that background task finishes, the launcher activity calls finish() to terminate itself.
If the background task is still not finished when activity B terminates, I want to avoid returning to the launcher activity. How can I do that?
I am thinking of using android:noHistory="true" in the definition of the activity in the manifest. However, the description of noHistory says:
"Whether or not the activity should be removed from the activity stack and finished (its finish() method called) when the user navigates away from it and it's no longer visible on screen". So I am afraid that the activity might be terminated before it finishes running its background task.
Is my background task guaranteed to be allowed to run to completion? Is there some better way to do this?
Make is simple. Start a background task in your application instance and clean-up preferences there. This will allow you to finish your "dispatcher" activity immediately after it started a next required activity.
Regarding excluding the activity from the back stack. There are two options. You can either define "dispatcher" activity with android:noHistory="true" in manifest file, or start "dispatcher" activity with FLAG_ACTIVITY_NO_HISTORY. Both options will exclude the activity from back stack.
Also, if "dispatcher" activity is in background, Android might decide to destroy it at any time. This might lead to unexpected results. With proposed soliton you have no such issue either.

Intent not restored correctly after activity is killed if clear top and single top flags are supplied

In my application there is an activity started using the FLAG_ACTIVITY_SINGLE_TOP and FLAG_ACTIVITY_CLEAR_TOP flags because I want to make sure that only one instance of that activity is at the top of the stack and all activities on top of the old instance are closed. So far so good.
Next I wanted to test if the activity restores correctly after being created more than once and successively destroyed. I take care to manually set the intent using Activity.setIntent() when Activity.onNewIntent() is called so that the most recent intent is returned by Activity.getIntent(). In order to test that I activated the "Don't keep activities" option in the developer options, but the intent returned by Activity.getIntent() when the activity is re-created is the very first intent that created it and not the most recent one.
This happens on JB and ICS, I haven't tested it on older versions. Am I doing something wrong or did I misunderstand something in the docs?
If you kill your app while it is in the foreground, this is not the same as when Android kills your app (which it will only do when your app is in the background). If you kill and then restart the app, it is like starting it all over again from scratch. There is no "restore" going on here. If you add logging to onCreate() you should see that after you kill and restart your app, the Bundle that is passed to onCreate() is null.
Unfortunately it is pretty difficult to simulate what happens when Android kills your app.
EDIT: Added more stuff after OP's comment
Here's a concrete example for discussion purposes. First without the developer option "Don't keep activities":
ActivityA is the root activity
We start ActivityA
ActivityA.onCreate() is called
ActivityA now starts ActivityB
ActivityB.onCreate() is called (The activity stack now contains ActivityA->ActivityB)
ActivityB starts ActivityA with FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP and an extra "foo"
ActivityA.onNewIntent() gets called with the Intent containing FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP and an extra "foo"
ActivityB.onDestroy() is called since the activity stack was cleared back to ActivityA
Now, let's do the exact same thing but enable the developer option "Don't keep activities" (I've highlighted in bold the stuff that is different from the previous scenario):
ActivityA is the root activity
We start ActivityA
ActivityA.onCreate() is called
ActivityA now starts ActivityB
ActivityB.onCreate() is called (The activity stack now contains ActivityA->ActivityB)
Because ActivityA has stopped, Android destroys it and calls ActivityA.onDestroy()
Note: The activity stack still contains ActivityA->ActivityB, even though there is no instance of ActivityA at the moment. Android remembers all the state
ActivityB starts ActivityA with FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP and an extra "foo"
Since Android has no instance of ActivityA to reactivate, it needs to create one, so it does and then...
ActivityA.onCreate() is called with the same Intent that it was called with when the original instance of ActivityA was created (ie: LAUNCH intent with no flags and no extras)
ActivityA.onNewIntent() gets called with the Intent containing FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP and an extra "foo"
ActivityB.onDestroy() is called since the activity stack was cleared back to ActivityA
The important thing to note here is that Android always calls onCreate() whenever it creates an activity instance. Think of it like the constructor of an Activity. If Android has to recreate an instance of an Activity because the process was killed or the activity was destroyed, then it will instantiate a new object, then call onCreate() and then (if necessary) it will call onNewIntent().
When you call setIntent() this doesn't actually change the Intent that Android saves and restores. That only changes the in-memory Intent that will be returned from a call to getIntent().
I hope this is clearer now. If not, please let me know.
Not sure if you've found a solution to this or not, but overriding the onNewIntent(Intent theNewIntent) method for the target activity & calling setIntent(theNewIntent) solved it for me.
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
/*
* This overrides the original intent.
*/
setIntent(intent);
}

android -- question about singleTask mode

after looking up the 'Defining launch modes' section of the 'Tasks and Back Stack' guide , I dont understand exactly the behavior of an activity declared with "singleTask".
assume that I start a singleTask-activity (via startActivity method ) when there is an instance of that activity laying at the bottom(root activity) of a background task,
as the article describes, the Intent I use to start singleTask-activity will be delivered to the instance, in this case, does the instance bring itself to top of its task and its task to foreground, or just bring its task to foreground without bringing itself to top of its task?
Do I make myself clear? pls help! thanks in advance
I was/am having the same question actually.
After reading replies here on stackoverflow and doing some experiments, I believe that when a singleTask activity is launched while it's already in a background task, the system will kill all other activities at the top of the stack and resume the singleTask activity.
For sure, this is not what I got out of the documentation though.
Here is my theory:
Launch Modes: Activity A: singleTask , Activity B: standard
experiment 1
Launch A ; stack: [A]
Launch B from A; stack: [A|B]
Press home; stack: [A|B]
Launch A from launcher; Stack: [A] (onDestroy was called on B
before onResume() on A)
experiment 2
Launch A ; stack: [A]
Launch B from A; stack: [A|B]
Launch A from B; stack: [A] (onDestroy was called on B
after onResume() on A)
In my case, I had to use android:alwaysRetainTaskState="true" although this is not ideal as I do want the stack to be cleared after, say, 10 minutes as this recommendation makes sense:
If the user leaves a task for a long
time, the system clears the task of
all activities except the root
activity. When the user returns to the
task again, only the root activity is
restored. The system behaves this way,
because, after an extended amount of
time, users likely have abandoned what
they were doing before and are
returning to the task to begin
something new.
from the Tasks and Back Stack guide.
I hope this helps other people.
If the Activity already exists it will call onNewIntent() for that Activity. Since an Activity is always paused before receiving a new Intent, onResume() will be called shortly after onNewIntent() is received. The fact onResume() is called means the Activity will come to the foreground and be visible to the user.
Then how does FLAG_ACTIVITY_CLEAR_TOP is different from Single Task?
Is the difference only that FLAG_ACTIVITY_CLEAR_TOP is a subset of single task, which only works the same way as but only if the activity being invoked is part of the current task?

Task Killer not resetting stack

My application has a main Activity A and that does a StartActivity on Activity B. If somebody uses a Task Killer (e.g., Advanced Task Killer), the application is killed but when they run the app again I see the Application object is being built (onCreate called) and then it goes right into Activity B not Activity A. The Manifest has A being the Launcher Activity.
I also see the scenario if I run A, then Activity B, bring down notification list and run Task Killer to kill my app, and press the Back key, it creates the Application object and then Activity B object.
Any ideas on how to prevent this behavior? Activity B assumes that Activity A has already run. I am able to kludge this but have a boolean in the Application object which is set on Activity A. In Activity B onCreate, if that global flag is not set, I do a finish(). Must be a better way to handle this since I have quite a few activities that would experience the same behavior.
Activity B should almost never assume any other Activity has run. Activities are meant to be stand alone units. If B must depend on A then there should be some test for a precondition and if it fails, opens ActivityA via an Intent.
Instead of keeping the flag in Application you may persist it in SharedPreferences - then your Activity B will always know the correct value of the flag.

Categories

Resources