I understand that intents are used to start new activities and services and can contain information about these - certain UI options, etc. They can be emitted by some activities or apps to signal that others should begin or end, or that some change should occur.
I don't understand how these are handled by the System at runtime. Do these go to the OS, where they are relayed to the place where they are needed, or do all Activity instances constantly check every single intent that is emitted, to see if they apply?
Also, on that note, can all Activity instances "listen" to all intents and if not, how is this "listening privilege" given?
Do these go to the OS, where they are relayed to the place where they are needed
Yes. After all, the majority of the time, the activity that is to be started does not presently exist.
Also, on that note, can all Activity instances "listen" to all intents
Activities do not "listen" on any Intents. Activities, via the manifest, describe what Intent structures they are interested in, via <intent-filter> elements. The OS then determines the activity to handle any particular startActivity() call (perhaps with the help of the user, via a chooser UI) and starts that activity.
Related
(The title is a bit weird because the words "code" and "app" are apparently forbidden in question titles.)
I have two Android apps, one is a normal unprivileged app and one is a system app with the permission to shut down the system. From my normal app I want to initiate the shutdown. I know the package name and I have full control over both apps. Both are signed with the same key.
What is the most concise way to run code in one app from another?
One way would be a Service that I can then start with intent.setComponent(...); startService(intent), but being a Service implies some background activity is going on, which isn't in my case.
Another way would be a BroadcastReceiver but that doesn't allow me to target a specific component, it requires an identifier whose purpose is conceptually to be received by other apps as well.
Is there another way with better fitting semantics?
but being a Service implies some background activity is going on, which isn't in my case.
Service using AIDL is simply an inter-process communication (IPC) mechanism. What the recipient of that communication does in response to that communication is up to it.
Besides, you have some background activity going on. You wrote:
From my normal app I want to initiate the shutdown
Shutting down a device is "background activity", at least in my interpretation of the expression.
Another way would be a BroadcastReceiver but that doesn't allow me to target a specific component
Sure it does. You can use setComponent() on a broadcast Intent the same way that you do for binding to a Service, or starting a Service, or starting an Activity.
There are downsides of using setComponent(), notably a dependency between the two code bases. Basically, the ComponentName becomes part of the API contract, and since that maps to a Java class name, you are limited in your ability to refactor that class (new name, new package). However, there's nothing stopping you from using setComponent().
For example, I describe using setComponent() for a broadcast in this blog post. In that case, I am deriving the ComponentName values via PackageManager, but that's just in service of this specific example.
Is there another way with better fitting semantics?
For a single interaction, "fire and forget" sort of thing, where you are not looking for any sort of acknowledgment, I'd send an explicit broadcast (i.e., a broadcast of an Intent that uses the ComponentName to identify the recipient). And I'd definitely use a signature-level permission to secure it.
While CommonsWare's answer is excellent and the explicit broadcast with a custom permission is usually the way to go, in this particular case I ran into an issue.
Apps cannot receive broadcasts until they have started an activity because until then they remain in "stopped" state. So an app with only a BroadcastReceiver won't work.
And since I need to have an activity anyway, I put the shutdown code in the activity.
I am developing an Android data entry app that saves the entered data to a file. A Service (let's call it FileIOService) is launched using the filename, and loads and saves data that is passed to it from each Activity that the user accesses.
I am trying to make the whole app as robust as possible, and at the moment I feel I need to pay particular attention to the interaction between each Activity and the Service. Here are the issues I can see:
If the Service is killed by the system, it needs to restart and open the file that it had open: I can handle this by using START_REDELIVER_INTENT.
If an Activity is destroyed, for instance by an orientation change, it needs to reconnect to the Service.
The thing is, once the Activity launches the Service, there's a while before the Service finishes opening the file and becomes ready for I/O requests. To address this, in my Activity, I have both:
an inner class subclassing ServiceConnection, with its onServiceConnected() method completed
a private reference to an anonymous inner subclass of BroadcastReceiver, with its handleMessage() method completed. This gets called when the Service sends out a broadcast to indicate it's finished opening its file.
Both of these methods then call a setUpActivity() method that pulls data from the Service. This is where it starts to get ugly. Because onServiceConnected() may run before the file is ready for I/O, and handleMessage() might be called while the Service is not bound to the Activity, I have to make both handleMessage() and onServiceConnected() set boolean flags that can later be checked in setUpActivity(), like this:
if ((fileLoaded && serviceConnected))
{
//access the file data
}
As I said, this feels ugly and awkward, and relies on setting extra boolean variables.
There's another problem - if my Activity launches an external Activity, like the Camera app, upon returning to my app the Service and Activity may both have been destroyed (especially with an orientation change) and the app crashes.
My feeling is that I may be missing some overall pattern that would define how each Activity should relate to the Service, and vice versa, while remaining robust and able to cope with unexpected terminations/restarts.
Let's ignore the fact that I am skeptical that this is a valid use case for a service (a service whose existence is simply to read and write files?).
If the Service is killed by the system, it needs to restart and open the file that it had open: I can handle this by using START_REDELIVER_INTENT.
The service is not "killed by the system". The process is killed by the system. This will eradicate your activities as well as your service.
The one possible exception to this is if the user manually stops the service (and only the service) from Settings, in which case I have no clue what the expected behavior would be. This should be fairly uncommon nowadays, particularly for an app that the user had just been using. Users will be more inclined to use a task manager, such as swiping your app off the recent-tasks list, which will get rid of the entire process, not just the service.
If an Activity is destroyed, for instance by an orientation change, it needs to reconnect to the Service.
Not necessarily:
Bind using the Application context (getApplicationContext()) instead of from the Activity directly
Use a retained fragment to maintain the binding across the configuration change
My feeling is that I may be missing some overall pattern that would define how each Activity should relate to the Service, and vice versa, while remaining robust and able to cope with unexpected terminations/restarts.
This is one of the many reasons why I try to avoid the binding pattern altogether. Use a service for processing commands, sent via startService(), with results (if any) delivered by LocalBroadcastManager, or Otto, or greenrobot's EventBus, or a "real" broadcast Intent, or maybe a Messenger. Particularly when the service is an IntentService, the service nicely cleans up after itself when there is no more work to be done.
I have the following situation: A service is running in the background of my application and regularly receives UDP packets. It uses an instance of my HandleMessageAgent class which analyses every message and shall start a new activity if necessary.
I would like to perform the following task: No matter which activity is in the front (as long as the service is running) I would like to inform the user about an incoming message under certain circumstances. I also need to update the information regularly as long as it is valid. Afterwards it should be closed automatically.
At first I thought about using a Dialog, but I think I cannot use it when the activity is not visible. Therefore I decided to use an activity, as it can be started from a service all the time.
I want to start the activity within the HandleMessageAgent object (in a method). My problem is, that I do not know how I can define an Intent to start an activity within an object, as the Context is not clear to me.
Is there a more elegant way to perform this task? Or can anybody help me with starting an activity from an object method within a service? Thank you!
There are two situations to consider:
When your service need to notify user your activities are not active, because some other app is active. In this case you should notify user via a system-preferred way: Android Notifications. You should not forcefully show dialogs or activities if user is using some other app. That's what notifications are for.
If one of your activities is active (no matter which) then your service should send a broadcast and interested activities should listen for it and act upon it. That way your service will not depend upon specific activity and will not need to keep track which activities are active at the moment the notification must be shown.
You can make your object Parcelable and add it to the Intent that will start the Activity.
Or you can put it in a subclass of Application because that instance is shared between your activities and your services (as long as they're in the same process)
You might need the "START_NEW_TASK" flag on the Intent
I am writing my first Android application, and I have been struggling with this for over a week. It seems like the basis of all android applications yet I cannot understand how to do it. For example, if you are in the Android Settings Menu, you have a list and you click on "About", it takes you to the "About" Actvitiy etc.
I need my app to do that as well, I have 5 menu items that I want to be able to select and go to the Activity for the selected item.
Currently I have my items in a string_array, but I have nothing that corresponds the string name with the activity name I want to goto.
Can somebody please give me some tips? I am really struggling over here, kind of overwhelmed with the documentation. Thank you in advance!
You should start from reading the Developer's Guide
A particular section you should note is the Application Fundamentals and Intents
Activating components: intents
Content providers are activated when
they're targeted by a request from a
ContentResolver. The other three
components — activities, services, and
broadcast receivers — are activated by
asynchronous messages called intents.
An intent is an Intent object that
holds the content of the message. For
activities and services, it names the
action being requested and specifies
the URI of the data to act on, among
other things. For example, it might
convey a request for an activity to
present an image to the user or let
the user edit some text. For broadcast
receivers, the Intent object names the
action being announced. For example,
it might announce to interested
parties that the camera button has
been pressed.
There are separate methods for
activating each type of component:
An activity is launched (or given something new to do) by passing an
Intent object to
Context.startActivity() or
Activity.startActivityForResult(). The
responding activity can look at the
initial intent that caused it to be
launched by calling its getIntent()
method. Android calls the activity's
onNewIntent() method to pass it any
subsequent intents.
One activity often starts the next one. If it expects a result back from
the activity it's starting, it calls
startActivityForResult() instead of
startActivity(). For example, if it
starts an activity that lets the user
pick a photo, it might expect to be
returned the chosen photo. The result
is returned in an Intent object that's
passed to the calling activity's
onActivityResult() method.
A service is started (or new instructions are given to an ongoing
service) by passing an Intent object
to Context.startService(). Android
calls the service's onStart() method
and passes it the Intent object.
Similarly, an intent can be passed to Context.bindService() to establish
an ongoing connection between the
calling component and a target
service. The service receives the
Intent object in an onBind() call. (If
the service is not already running,
bindService() can optionally start
it.) For example, an activity might
establish a connection with the music
playback service mentioned earlier so
that it can provide the user with the
means (a user interface) for
controlling the playback. The activity
would call bindService() to set up
that connection, and then call methods
defined by the service to affect the
playback.
A later section, Remote procedure calls, has more details about binding
to a service.
An application can initiate a broadcast by passing an Intent object
to methods like
Context.sendBroadcast(),
Context.sendOrderedBroadcast(), and
Context.sendStickyBroadcast() in any
of their variations. Android delivers
the intent to all interested broadcast
receivers by calling their onReceive()
methods.
For more on intent messages, see the
separate article, Intents and Intent
Filters.
Check how its done here in the Settings app. They use a PreferenceActivity and embed the Intent in the XML file.
<com.android.settings.IconPreferenceScreen
android:title="#string/radio_controls_title"
settings:icon="#drawable/ic_settings_wireless">
<intent
android:action="android.intent.action.MAIN"
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.WirelessSettings" />
</com.android.settings.IconPreferenceScreen>
I have an android app. I added an intent filter to one of my activities, so that if a url is clicked in the browser app, my activity can be launched. Looks like this:
<data android:host="www.mysite.com" android:scheme="http"></data>
this works well. The problem is that every time my activity is launched from the browser, a new instance of the activity is created, inside the browser app's task, instead of recycling any existing instance that may be in the system already.
This is a problem for me because this activity uses a singleton. If I allow more than one instance of this activity to exist, I can get into some weird situations where the two instances are in conflict when they try to share the singleton. I checked and can see that although the activity instances may be in separate tasks, they do share the same singleton instance.
An ideal solution for me would be if I could somehow bring a pre-existing instance of my application to the foreground, and launch or resume the target activity within whatever pre-existing instance of my app happens to be running.
So I tried this:
Register above filter to point to dummy activity which is just a catcher.
Dummy activity creates a broadcast intent, and tries to broadcast 'create me' message to system.
Real target activity is set to listen for this broadcast message. Hopefully if there is already an instance of the activity in the system, it will come to the foreground. If no instance yet, that's ok, allow creation in the browser task.
Not sure if this makes sense. My basic goal is to limit the activity to one instance in the system. The app is just social media app which has a login state that needs to be preserved. The singleton mentioned above preserves that login state, so I want to have only one around in the system, instead of allowing multiple login instances running around which would be a headache for the user.
Thanks
You can set the activity launch mode to singleTop to achieve this.
android:launchMode
An instruction on how the activity should be launched. There are four modes that work in conjunction with activity flags (FLAG_ACTIVITY_* constants) in Intent objects to determine what should happen when the activity is called upon to handle an intent. They are:
"standard"
"singleTop"
"singleTask"
"singleInstance"
The default mode is "standard".
https://developer.android.com/guide/topics/manifest/activity-element.html#lmode