How intents and startActvity works internally? - android

Everyone knows if you create intent to start another activity, you pass in as a parameter into startActivity. But I just thought about the possible scenario: intent says system "call this activity", the system sees manifest and then runs activity, or this running acts internally in the app, something like "call some method of some class"?
Probably a stupid question, but I couldn't find enough info. So how does it works?

Following is the way how intent communication works:
Activity A creates an Intent with an action description and passes it to startActivity().
The Android System searches all apps for an intent filter that matches the intent. When a match is found,
the system starts the matching activity (Activity B) by invoking its onCreate() method and passing it the Intent.!

Related

Why does the Main activity has an intent filter?

If the intent filters are to resolve implicit intents, then why does
the MainActivity(which is the very first activity that is run when
app is launched) has an intent filter?
Who send an implicit intent to it?
What if the sent implicit intent doesn't have proper data ?
Well, how does the system know which activity is the main activity? It isn't the name- the system doesn't care about the name. Its the activity with the intent filter that says its the main activity.
It can also have other intent filters to launch it any other way you may want. For example, you may have an intent filter to launch it via a deep link.
As for proper data- if launched from the app list or homescreen, it won't have any data. Its on the programmer of the app to make sure that it can do something that makes sense in that case.
It has CATEGORY_LAUNCHER and ACTION_MAIN .
android.intent.action.MAIN means that this activity is the entry point of the application, i.e. when you launch the application, this activity is created.
CATEGORY_LAUNCHER tells that your activity should be displayed in the top-level launcher.
https://developer.android.com/reference/android/content/Intent.html#ACTION_MAIN
Launcher sends implicit intent to it. This is how launcher knows which activity is to be opened on click.
If you send improper data it will not open your activity. For ex:
If you try to start your main activity using implicit intent only in startActivity then it will not start because there is CATEGORY_DEFAULT associated with it. You need to add one more intent_filter to your activity to resolve the intents.

How can I know the startActivity intent from other application?

I have an Activity and assume that has been launched. When the other application use startActivity method to start my Activity, my Activity will show and run the onResume Method, but I can't find any way to get the intent which is used in startActivity method by the other application. I want to get the extra data in the intent. How can I do?
EDIT
My Activity is singleTask, and I want to get the startActivity intents form other applications. I think it is not associate with filters.
Have you tried using getIntent() ?
Then you can do:
this.getIntent().getExtras();
After that if you need new intents just override the onNewIntent function in your activity.
I simply say an example. When we need to share something. We click share button which shows a list of app by which we can share our things.
So, if you want to make that kind of app which can receive other app data then you need make your activity capable of receiving that data. In order to receive implicit intents, you must include the CATEGORY_DEFAULT category in the intent filter in manifest.
Below this link you will get some more information : http://developer.android.com/training/basics/intents/filters.html

What happens when you click on an application's launch icon?

 What happens when you click on an app's launch icon?
Is a new intent always sent, or is the result sometimes the same as resuming a task from recent tasks?
If an intent is sent, when does it get sent to the onCreate() method of a new activity instance and when does it get routed through onNewIntent() of an existing activity?
Let's suppose the intent gets routed through onNewIntent() of an existing activity in the task. Which activity does it get sent to? The one nearest the top or the one nearest the root? Will it always get sent to an instance of the application's launch activity or can it sometimes get sent to an activity with the same affinity as the root? Can it ever get sent to an activity which does not share the same affinity as the root?
Finally, how is this all affected by the various launch modes (standard, single top, single instance, single task) of the activities in the task?
If there is anyone out there who understands all this, please help me!
What happens when you click on an app's launch icon?
Launcher apps calls startActivity with an intent [action = Intent.ACTION_MAIN, category = Intent.CATEGORY_LAUNCHER and flag = Intent.FLAG_ACTIVITY_NEW_TASK].
Regarding Intent.FLAG_ACTIVITY_NEW_TASK, from docs:
When using this flag, if a task is already running for the activity
you are now starting, then a new activity will not be started;
instead, the current task will simply be brought to the front of the
screen with the state it was last in.
onNewIntent basics:
onNewIntent is delivered only when activity has set either singleTask, singleInstance launch modes. It is also delivered if activity has set singleTop launch mode or the intent to start the activity has set the flag FLAG_ACTIVITY_SINGLE_TOP and the activity instance is already at the top of the target task. It means an attempt was made to launch a new instance of activity, instead the existing instance itself need to handle the intent.
Here is the response to your queries:
Is a new intent always sent, or is the result sometimes the same as
resuming a task from recent tasks?
If the task is already running, it is brought to foreground. In case FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET flag was used to launch a activity and latter the task is brought to foreground, then the activity is killed. From docs:
This is useful for cases where you have a logical break in your
application. For example, an e-mail application may have a command to
view an attachment, which launches an image view activity to display
it. This activity should be part of the e-mail application's task,
since it is a part of the task the user is involved in. However, if
the user leaves that task, and later selects the e-mail app from home,
we may like them to return to the conversation they were viewing, not
the picture attachment, since that is confusing. By setting this flag
when launching the image viewer, that viewer and any activities it
starts will be removed the next time the user returns to mail.
-
If an intent is sent, when does it get sent to the onCreate() method
of a new activity instance and when does it get routed through
onNewIntent() of an existing activity?
onCreate is called while creating a new instance of activity. onNewIntent is called if already an activity instance exists and no new instance need to be created, as in case of singleInstance, singleTask and conditionally singleTop (as described above).
Let's suppose the intent gets routed through onNewIntent() of an
existing activity in the task. Which activity does it get sent to? The
one nearest the top or the one nearest the root? Will it always get
sent to an instance of the application's launch activity or can it
sometimes get sent to an activity with the same affinity as the root?
Can it ever get sent to an activity which does not share the same
affinity as the root?
In case of singleTask and singleInstance it has to be root of the task. In case of singleTop it has to be top activity of the task.
Finally, how is this all affected by the various launch modes
(standard, single top, single instance, single task) of the activities
in the task?
I hope the explanation provided till now, answers it.
Update 1:
Here is the Launcher code which adds the flags to intent:
void processShortcut(Intent intent) {
....
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
....
}
void startActivitySafely(Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
...
startActivity(intent);
}
Your best bet is to read through the Developer docs here: http://developer.android.com/training/basics/activity-lifecycle/index.html
There is a flow chart in the first lesson(http://developer.android.com/images/training/basics/basic-lifecycle.png) which provides an excellent graphical representation of the Android activity life-cycle.

Do implicit intents do a broadcast internally?

Following piece of code open an URL using implicit intent.
EditText editText = (EditText) findViewById(R.id.url_editText);
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(editText.getText().toString()));
startActivity(myIntent);
It shows up all the applications that support this action Intent.ACTION_VIEW like Chrome, Firefox etc. Hence I am assuming this procedure internally does a broadcast with action Intent.ACTION_VIEW. Please correct me if I have misunderstood.
As per above assumption I tried the foloowing code
Intent myIntent = new Intent(Intent.ACTION_VIEW);
sendBroadcast(myIntent);
but it does not work. Nothing is shown. What is the difference. Can someone clear my confusion?
This has to do with IntentFilters. Before launching the Activity, it's asking the system to give it the list of everything that's an Activity and can handle the intent -- no broadcasting involved here.
As for sendBroadcast() -- it's essentially the same thing but for BroadcastReceivers. The mechanism is the same: match intent filters, deliver the Intent, but the Intent is delivered to all the receivers regardless of their quantity (as opposed to what startActivity() does -- because it can only result in starting a single activity, hence the need to choose one if there are multiple that match).
I don't think there are any BroadcastReceivers registered for Intent.ACTION_VIEW (since it's an action whose purpose is to start an activity, there's no logical reason to listen for it and start nothing, except count activity launches or something) but you can register one yourself and see what happens.
Hence I am assuming this procedure internally does a broadcast with action Intent.ACTION_VIEW.
No.
but it does not work. Nothing is shown
Of course.
What is the difference.
startActivity() != sendBroadast(). They are separate operations, just as addition and subtraction are separate mathematical operations.
If you wish to think of the Intent system as being a bit like a message bus, that bus has three totally separate channels:
activities (startActivity())
services (startService(), bindService())
broadcasts (sendBroadcast(), sendOrderedBroadcast(), etc.)
The difference between those two is just who receives the Intent. If you call sendBroadcast() the Intent will be sent to BroadcastReceivers. If you call startActivity() the Intent will be sent to Activities. That's the reason why this:
Intent myIntent = new Intent(Intent.ACTION_VIEW);
sendBroadcast(myIntent);
Doesn't start an Activity, because the Intent is only visible to BroadcastReceivers.
The same goes for startService(). By calling that method the Intent will only target Services. I guess the confusion comes from the word broadcast. It implies that it is sent everywhere and visible to everyone, but that is not the case. Broadcasts are only visible to BroadcastReceivers just like if you call startActivity() the Intent will only target Activities and nothing else.
You can find more information here.

Pending Intent: Can I specify a method to run in the receiving activity?

When a pending intent is sent, does it create a new activity? What if I have an activity already running? Is there a way to specify an already running activity, and have a method in that activity run once I send the intent?
What I want to do is have a button in a notification bar that acts a "stop" button, which will call the stop method in the already running application.
It depends on the Activity's declaration in the manifest, or the Intent flags that you include.
For example, if you use FLAG_ACTIVITY_SINGLE_TOP (or the activity has launchMode set to "singleTop") then onNewIntent() will be called on the existing activity instead of creating a new one.
In your example, you should pass an extra in the intent to indicate that you want to execute the "stop" action, then check for it in onNewIntent().
This is well explained in the official documentation about launch modes: http://developer.android.com/guide/components/tasks-and-back-stack.html#TaskLaunchModes
EDIT: However, since the ultimate objective was playing audio in background, using a Service is a more appropriate option. Check http://developer.android.com/guide/topics/media/mediaplayer.html#mpandservices
To control the service from the notification (i.e. play, pause, stop) you need to supply PendingIntents created from with startService().

Categories

Resources