starting android service using explicit vs implicit intent - android

According to the standard Android documentation, the prefered way to start a service (started service that is) is to use an explicit intent like this:
// Using explicit intent:
Intent serviceIntent = new Intent(getApplicationContext(), MyService.class);
// or:
Intent serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);
You can also start/stop a service using an implicit intent with an action string specified in the manifest, like this:
// Using implicit intent:
static final String serviceAction = "com.example.my.app.services.MYSERVICE";
Intent serviceIntent = new Intent(serviceAction);
startService(serviceIntent);
// AndroidManifest.xml:
<service android:name="com.example.my.app.services.MyService"
android:exported="false" android:process=":services" >
<intent-filter>
<!-- Start/Stop service -->
<action android:name="com.example.my.app.services.MYSERVICE" />
</intent-filter>
</service>
When the service is used only locally (third party applications are not allowed to start or bind to it), the documentation says that you should not include an intent-filter in the manifest service tag and you should set the exported tag to false.
Note: the activities and services run in separate processes (:application and :services processes). The communication between activity and service is done by implementing AIDL interfaces (this is done because only AIDL remote interfacing allows me to do multi-threading within the service that needs to handle IPC simultanously, not only between activities but mostly between services running within the :services process).
My questions are:
Q1: When the activities and services I use in my app are run in two different processes, do I need to use implicit intents over explicit intents to start and stop the services?
Q2: When the :application process is gone (destroyed, not in memory anymore) and the :services process is running in the background, how do I connect again from a new :application process to the already running :services process? Somehow I need to get a reference to the :services process again so that I can stop the running service inside that process. This cannot be done using AIDL afaik.
The problem is that Android can and will destroy the :application process easily when out of resources, and that is fine by me as long as the :services process keeps running.
(Yes, I know about influencing the process by setting the service as a foreground service, etc. I too can read manuals ;) but that is not my problem).
I cannot find any information or answers related to my questions when the activities and services are in separated processes and use AIDL, AND when the :application process needs to "find" the :services process again after it has been killed by Android or when the user enters the app again (after he/she left the app before).
Any expert-level advise is welcome.

A1 : Even though your activity and service run in different processes they still belong to same Application. You can still use explicit intent, I don't see any specific advantage of using implicit intent here (let me know if find any :) )
A2 : let me list down few facts here
Life cycle of "Started" service (rather than "Bind"ed service) is independent of the life cycle of Activity which has started this service. This is true irrespective whether both are running in the same process or not.
Only one instance of Service will be alive at any point of time. when your activity calls startService() , service instance will be created if it is not already running (in this case you service will receive onCreate() callback as well). But if Service is already running, Framework would simply call onStartCommand() callback on already running process(No onCreate() callback in this case). Again all this is true irrespective of activity and service are running on same process or different processes.
Now to answer your question, if you service is still running (because of startService() call by previous activity), then bindService()/startService() will make sure to connect to existing service.
Hope this is of some help to you. Let me know if you have any other specific questions.

You don't need to use an implicit intent to start a service or activity in a separate process; however, using a separate process for an Activity is a rare scenario. Using a separate process for a Service is more common, but nevertheless I'd like to know what the use case is.
If your application process is destroyed and then restarted, you'd use startService to reconnect to the Service. If the Service is running, you connect to it, otherwise the Service is restarted. If you then want to kill the Service, you can kill it, or you can run stopService() from your main app.
What is the service doing?

Related

Is there anyway to create a background process service that will run whether or not the app created it is still running?

So, I want my app to create a Service that will initially run in the background and do some stuff. This background process will never stop. It will constantly keep running. The ONLY way the background process can be created or destroyed would be through the app. I understand that there are endless possibilities to kill a process. I guess I want my app to be able to tell me whether or not the process is running and retrieve real time information from that process. Along with that, be able to start and/or destroy the background process.
So, let's say that you were to open the app and start/create the service. Even when you close/terminal/call onDestroy for the app, I still want the background process to be running. The only way to destroy this service would be to re-open/re-create the app, and destroy it.
Does Android allow something like this? Is there a way to get around this?
I was going to create a IntentService and make it run an infinite loop. Though, my only problem is how to obtain information from the IntentService. From what I've learned, an IntentService is created and kills itself when it's done.
I'm still new to Android, so don't hesitate to be specific and/or remedial.
Answer is quite simple.
Create a Service (not IntentService, just a simple Service) and start it from your activity. IntentService will not work in your case as it will call stopSelf() on itself as soon as you return from onHandleIntent()
Your service will continue to run till somebody explicitly calls stop method on it or service itself calls stopSelf() method. But in low memory conditions, platform can kill your background services. When device has enough memory platform will restart your service provided you make your service STICKY by returning START_STICKY in onStartCommand().
call stopService() from your activity when required. It doesn't matter even if your activity got stopped/killed and restarted.
You dont really require to launch your service in another process. Because platform will make sure to start and keep your application process alive as long as any of its entities (Activities, Services, Receivers) are alive. Dont worry, your application will not appear in running apps list if your process is running but none of its activities are alive.
Hope this answers your question.
You dont need to make 2 apps for that, in fact, if your requirement is to only be able to stop/create the service from the main app it will only overcomplicate things (such as that you dont need aidl at all since its all in the same app) , that goes for the above answer (cant reply yet!).
Just create the app and the service class even on the same package as the other activities. Then on the manifest xml register the service like this at the application node:
<service
android:name="com.example.yourpackage.Service"
android:process=":remote">
<intent-filter>
<action
android:name="com.example.yourpackage.Service" />
</intent-filter>
</service>
What you are doing with the android:process=":remote" tag is explicitly setting the service to run in a different process (by the name of 'remote') than the rest of the app while still being part of it.
Then, to start and stop it simply use these from your activity:
startService(new Intent(this, Service.class));
·
·
·
stopService(new Intent(this, Service.class));
Make sure you read the documentation about services (and broadcastreceivers) anyway, but that will give you a general idea as to where to aim and what NOT to do to overcomplicate.
I've been working with services lately so im fresh on the matter, if you have any questions let me know here!
<<<<<<<<<<<< EDIT : >>>>>>>>>>>>>>>
Ah I think I get you now.. if you dont want the service to keep running after the "app" is finished just forget about the :remote part. That way they will both share same app lifecycle (but not context lifecycle as they have different ones), sorry if that part confused you and thanks for the vote!.
Just make 2 apps. one a service and one an app. (since the service & the app run on the 'UI' thread).. That way you have two separate processes. Use aidl to communicate between the two.. Would not use intent service, those are supposed to be short lived.
The solution the user SupressWarnings gave you is correct, except that you will be forcing the Service to run in a separate process, and I don't think you will be interested in that. It will only help you in keeping your service running even after the main process dies (probably because of an unhandled Exception), but the fact is that the main process should never die if you have a service running. And the problem with having your service in a separate VM process is that you will lose the ability to use the same memory space, so singletons, statics variables, etc., won't work as expected. And additionally every call from the main process to the service process will be serialized through the binder mechanism which incurs in speed penalties and limits the serialized data to not go beyond 1MB (which could happen if you pass a big byte array for example).
So my opinion is that you should use the SupressWarnings solution without the android:process attribute.
I ran into the same problem and I fixed it by calling startForeground() within my onStartCommand() of a regular Service, not IntentService. I recommend you make the switch to a regular Service as mentioned above.
Here is my code. Call this method in your onStartCommand():
final int id = 1234;
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendIntent = PendingIntent.getActivity(this, 0, intent, 0);
//Build the notification
Notification.Builder builder = new Notification.Builder(getBaseContext());
builder.setContentIntent(pendIntent);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setTicker("message");
builder.setWhen(System.currentTimeMillis());
builder.setAutoCancel(false);
builder.setContentTitle("Test Service");
builder.setContentText("message");
Notification notification = builder.build();
//start foreground service
startForeground(id, notification);

Why my Android Service is killed when I launch an Activity from it?

I have a Service that has to launch an external Activity.
I would like that even after have launched the Activity, that Service will continue to be running. The problem is that the onDestroy() is invoked and the service is killed.
here it is my code:
How I start the external Activity from inside the Service:
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Any idea?
Is it normal that when I start an activity from inside a Service, that Service is being killed?
Services are not "killed".
Your service will run until:
You call stopService() referencing the service, or
The service calls stopSelf(), or
If you are using the binding pattern, all bindings (via bindService()) are unbound (via unbindService()), or
Android terminates your process, such as due to low memory conditions or by user request
Hence, you need to determine which of the conditions is true. None necessarily have anything to do with starting an activity.
Note that starting an activity from a service is generally not a good idea, particularly if this may occur at arbitrary times rather than based on user input. Users dislike activities appearing out of nowhere.

Android Background Service is restarting when application is killed

I am developing an application in which a background service is created to collect sensor data. I am starting the service from my activity:
startService(new Intent(this, MyService.class));
I created the service so if the application is destroyed, the background service still continues to collect data. I tried this, and it worked to a certain extent. My problem is that when I kill the application, the service seems to restart because the onCreate() service and the onStart() methods are invoked. Is there any way with which the service isn't restarted please?
UPDATE:
As suggested in an answer below, I added the following method in the service but no luck.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
It depends on the value returned in onStartCommand.
You must return START_NOT_STICKY
According to the documentation:
For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them
In short:
If you return START_STICKY the service gets recreated whenever the resources are available. If you return START_NOT_STICKY you have to re-activate the service sending a new intent.
Since all of this triggered my curiosity, I made a sample app to test this. You can find the zip with all the sources here
There are a startService button and a stopService button that do what you would expect from them.
The service returns START_NOT_STICKY in onStartCommand.
I placed toasts in onCreate, onStartCommand and onDestroy.
Here what happens:
If I press start, onCreate and onStart are called
If I press stop, onDestroy is triggered
If I press start twice, onCreate is called once and onStartCommand twice
So it behaves as one would expect.
If I start the service and kill the app as you described, onDestroy does not get called but neither onCreate or onStart.
If I get back to the app and I press start again, onCreate gets called which means that, as I wrote before, START_NOT_STICKY prevents the service to getting restarted automatically.
I guess you have something else in your app that starts the service again (maybe a pending intent).
The app and the service live on the same process, which means when the app is killed so is your service. Changing the return value of onStartCommand doesn't affect this process. It simply tells the Service to either start/stop when you tell it or when it's finished doing what it needs to. As mentioned in your comment to your original post, setting it as a foreground process worked, but that's really just forcing the service to have a high priority, not solving the problem.
To change the Service so that it's killed separately and assuming it's a started service rather than a bound service due to the use of onStartCommand, specify a process name in the manifest for that Service.
From the Process and Threads Developer Guide:
The manifest entry for each type of component element— <activity>, <service>, <receiver>, and <provider>—
supports an android:process attribute that can specify a
process in which that component should run. You can set
this
attribute so that each component runs in its own process or so
that some components share a process while
others do not. You can also set android:process so that
components of different applications run in the same
process—provided that the applications share the same
Linux user ID and are signed with the same certificates.
Android might decide to shut down a process at some
point, when memory is low and required by other
processes that are more immediately serving the user.
Application components running in the process that's
killed are consequently destroyed. A process is started
again for those components when there's again work for them to do.
From <service> in Manifest File:
android:process
The name of the process where the service is to run.
Normally, all components of an application run in the default process
created for the application. It has the same name as the application
package. The element's process attribute can set a
different default for all components. But component can override the
default with its own process attribute, allowing you to spread your
application across multiple processes.
If the name assigned to this
attribute begins with a colon (':'), a new process, private to the
application, is created when it's needed and the service runs in that
process. If the process name begins with a lowercase character, the
service will run in a global process of that name, provided that it
has permission to do so. This allows components in different
applications to share a process, reducing resource usage.
Not sure why the other answer that mentioned this was down voted. I've used this method in the past and, today, created a simple one Activity app with a Service on a different process just to make sure I wasn't crazy. I used Android Device Monitor to kill the app's process. You can see both, separate processes in ADM and can see that when the app's process is killed, the Service's is not.
Start not sticky doesn't work above kitkat, and the other onTaskRemoved not working above Marshmellow.
onTaskRemoved could be used by handled some exceptions. Did not worked on that. But try that one.
If you are using an IntentService, it has an
onHandleIntent()
method where you should place the code that needs to be executed. It is executed in a separate thread (not a UI thread where your application runs) therefore your app shouldn't affect it. When the code has finished executing, the thread is terminated and the service is stopped automatically.
I ran into the same problem and was able to resolve it by making the service run in a global process. You do this by adding the following to the manifest tag:
process="com.myapp.ProcessName"
(Make up whatever name.)
When I did this I found that my service wasn't killed (and restarted) when the app is swiped off the list. Presumably this is because the app process is killed when you swipe it off, but global service processes are not.
The disadvantage of this is that communication between your app and service now has to be via the IBinder interface; you can't directly call functions in the application or service from the other one, because they're running in different processes.
I know its much late to answer this question, but may be it can be helpful to others. This really helped me for my Music Player App.
If there are services which can be disruptive or can affect the user experience like music etc , then in that case you have to use Notification and when service is started successfully, then create the Notification and use the function
startForeground(int Notification_id,Notification);
This will run your service in background without restarting and reinvoking its methods
https://developer.android.com/reference/android/app/Service.html

Android Service is running, but it doesn't show up in settings -> running services

I have a service in my app, as some other apps have, too. From what I am used to, I can see (and kill) services nicely in settings -> (running) services. But: not mine...
The service itself is extended from IntentService. It is handling Alarm Intents via BroadcastReceiver and also messages from my app and back to do some work. As it's essential to my app and keeps some remote web session and other (read: "a lot of") persistent data, I do explicitly start it in main activity with
startService(new Intent(this, HeartBeatService.class));
and in the service, I even use
startForeground(NOTIFY_RUNNING, runNotification);
Other of my apps' activities using the service just using bindService(), working like a charm.
It really is running. Perfectly and always, as I wished, even if the activities get killed by android because of whatever android thinks it's good for.
Just: I don't "see" it running.
I also tried overrriding the service onStartCommand() to return START_STICKY, but nothing changed. I know, this one should not be overwritten in IntentService.
Or am I just thinking wrong somehow? Is IntentService "different"?
Thank you!
From the Android documentation reference:
IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Your service will only run when it receives an intent and stops once it is done doing what that intent had it do.
Also, I've found that services bound to activities will not show up in the running services screen.
Once you remove the binding, they show up.

How does intents handle multiple services or classes of the same type?

Say I have an application, where there is a service running in a loop, this service is started by an intent. I then have another application (the same, but with a different AppID) wanting to start the same service, while the prime service is still running. How can intents handle this? (Note: I want both services to run at the same time...)
I'm looking for an understandable answer that explains the "HOW" behind it, not as much: "well this code takes care of THAT!". It's no problem if your answer doesn't fit my example, as I'm still VERY new my question might be asked in an odd (or even dumb) way, I apologize beforehand.
Thanks!
- Bobby
A Service has to be declared in the AndroidManifest.xml: this specifies the Service class. You can launch the Service using either an explicit Intent (specifying the service class (and optionally the component name)) or using an Intent that will match an IntentFilter associated with the service.
Case 1 is using an explicit Intent. If only 1 app registers the class as a Service then in your second app you will have to use an Intent with a ComponentName that wll start the first app's copy of the service. In this case, only 1 instance of that Service class will be active. If both apps register the class as a Service your intent will launch a second instance of that Service class.
Case 2 is using an IntentFilter. If both Service declarations use the same IntentFilter then IntentFilter priorities kick in: the Service declaration with a higher priority fires off, and will essentially always win, so you will only ever have 1 instance of that Service class running. If both Service declarations have the same priority then its a tossup which one gets used.
In any case there will be (for any 1 Service declaration) at most one copy of that service running at any time. You can get crazy with "remote" process declarations but that's about it I think.

Categories

Resources