My question is very simple. I have a foreground service that, when activated, runs indefinitely until the user stops it. In the I MainActivity, I need to know if the service is running or not (image if the user closes the app but the foreground service is still running, when he reenters the app, I need to know if the service is already running). Is it viable to have a companion object on the Service with a status variable so that I can access its status?
Something like this:
#AndroidEntryPoint
class SomeForegroundService: Service() {
companion object {
var status = 0
}
....
And then somewhere in my MainActivity...
SomeForegroundService.status == 1
Is this prone to memory leaks? Whats a better solution (not counting with checking every running system service)
What you need is to bind the service
https://developer.android.com/guide/components/bound-services
If you use bindService(intent, connection, 0) without the Context.BIND_AUTO_CREATE flag, it will only bind to existing service, and return false if the service does not exist.
You can use this method to check is service is running or not instead of static variable
// check and return true if service is running
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (TrackingService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
Edit :
If you don't want to check every service, you can register broadcast receiver in the service and it pings the activity.
Original Answer by : How to check if a service is running on Android? (answer by Ben H)
Related
I have a little specific issue and I want some tips for that. I need to start just one time an Android service, and I can use these 2 options:
Start the service from the onCreate() method of the MainActivity. The problem with this way is when the device is rotated with my app running, the onCreate() method is called again, because the MainActivity is restarted and I don't want that my service restarted because of this.
Start it from the Android Application class. The problem is that before start the service, I need to check if some permissions was accepted by the user. So the first time that my application is started in the Application class the permissions are not accepted yet.
Reading this article Handle configuration changes I can see that is possible avoid the restart of my MainActivity but I don't know if this is a good practice. So maybe exist some way to request user permissions from the Application
onCreate with be called once during Service lifecycle, but onStartCommand will be called every time you call startService
You can't request user permission outside Activity context. So, you can run service but you are unable to do something that requires permission. You may register BroadcastReceiver inside your service for catching some "permission granted" intents. But this intent should be created and sended to service via broadcast in Activity context at the moment when user grants permission. Or you may use service commands instead
To prevent restarting your service just check in your MainActivity onCreate method is your service running
Function for checking service running:
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
And after that you just need to call it in your onCreate method:
#Override
public void onCreate(Bundle savedInstanceState) {
if(!isMyServiceRunning(MyService.class)) {
//start your service
}
}
I am not sure the reason why you would like to start the service only once but I am gonna try to suggest an alternative to achieve this.
Since you would like to ask for a user's permissions, the service cannot be started in the application class. So the only place you can start it is in the activity class.
The key to solve this will be the onCreate and onStartCommand methods.
If you define the service in the manifest file and then call Context.startService(context) multiple times, onCreate will be called only once as long as the system has not killed the service yet.
onStartCommand will be called every time you call Context.startService(context).
Hence in this approach, write the block of code that you need to be executed once in the onCreate method. For all updates, execute them in the onStartCommand method.
Another option would be to dig deeper into android architecture components (LiveData, LifeCycle and observers)
I think the best way to deal with android's infamous rotation is to use ViewModel. As ViewModel survives device's rotation you can store a liveData of boolean initially set to true and observe it in onCreate(). Start the service only if the observed value is true and set it to false once you have started the service. Please see the following example,
In ViewModel
val startService = MutableLiveData<Boolean>(true)
In Activity's onCreate()
viewModel.startService.observe(this, Observer {
if (it) {
startService()
viewModel.startService.value = false
}
})
I have a public class Tracking extends Service witch is called from practically every activity with something like this:
Intent serviceIntent = new Intent(this, Tracking.class);
serviceIntent.putExtra("name", "Tabla3b Kras");
serviceIntent.putExtra("time", TimeGenerator.getTime());
startService(serviceIntent);
And that works fine, public void onCreate()is called only the fisrst time and, public int onStartCommand(Intent intent, int flags, int startId) is called every other time.
The problem I have is that when the user closes the app. Let's say double back press or going in the open apps list and dismising it. I get a "Unfortunately, "appname" has stopped working.
I know that I can close the service in onStop(), but since I am calling the service from almost all the activities do I have to implement onStop() in all of them or is it enough to just do it in MainActivity.java? And will the service stop if the user changes between activities?
Service is a background process. It is not meant to start/stop from every activity.
You can start your service only once in your app. Like you started in your first activity (splash) or application level class. You don't need to start service in every activity.
Same you don't need to stop your service from every activity. You can stop your service once when you handle onBackPress().
How do I then pass variables to the service from other activites?
There are several ways you can communicate between Activities & Services.
Use Binder. You can follow this answer.
You can use Handler. Follow this.
You can use BroadcastReceiver. Follow this.
Use EventBus by GreenBot. This library is getting popular now a day becasue of ease of implement.
If you ask my preference, I used BroadcastReceiver & Binder earlier days. But now I use EventBus. You can simple implementation steps in EventBus documentation.
Suggestion:
Check if your service is already running or not. Start service before use if not running.
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
I have a Foreground Service for my app, which must run the whole time and never stops. While I was testing it few times, it seems after 3-4 days Android decides it just to stop it, and never restart it again, and in my Activity I have a check for the service if its running, and if it isnt to start it.
Even though, the service is not starting, and I can't debug it, because this is not happening immidiatelly.
So this is my check, is there something wrong in it?
if (!isMyServiceRunning(MyService.class)) {
startService(new Intent(this, MyService.class));
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
I call this check in onResume() of the Activity, and I can't just run it everytime when the activity starts, because I have a constantly running Thread in the service, which will get more than one instance if started several times...
So here is what I want:
Either have more reliable way to check for the service if its running
or
Just start the service every time the activity starts, to prevent problems, and the thread inside of it must always have just 1 instance (I have already declared is as static)
You can make your service Bindable and bind your Activity to the service when the Activity starts/resumes. This way you will be sure the service is running. But I think you have a problem with your service. My I ask you to post more information about the service? It is not normal the OS to kill a foreground service with no traces.
what is the best way to implements a service from starting with alarm manager when android applications first starts?
Right now i have a Home activity which is the first page of the activity which runs the service when it is being created. However when the users were to start the application again on the app menu (when the application is running.), the home activity will be run again and the service will start again.
Is there any better alternative for this way of application?
Follow this link... have a look at the implemenation below.
http://blog.gregfiumara.com/archives/82 ...
and for the checking whether a service is active or not... you can simply use this.
private boolean isMyServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if ("com.example.background.BootableService".equals(service.service.getClassName())) {
return true;
}
}
return false;
}
Use this in the any class you want to check for a existing service... and if no service is present then just create one or else you are good.
Let me know how it works out.
I have read the other threads about checking if a service is running but this is not working for me.
My situation is that am creating a background web server service but not binding to it because I want it to continue running after the activity ends. The service creates a notification so users can see it is running. The user can stop the service through a button on the Activity.
This is all working fine, except on launch of the activity, I can't determine if the service is already running. Am using the following:
if (isMyServiceRunning() == false)
{
Intent ws = new Intent(this, WebServerService.class);
startService(ws);
}
And this
private boolean isMyServiceRunning() {
String sClassName;
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
{
sClassName = service.service.getClassName();
DebugMsg("Service: " + sClassName);
if (sClassName.contains("com.<mydomain>.webservice"))
{
return true;
}
}
return false;
}
I get a list of services running, for both system and 3rd party services. But my service doesn't show up in the list, even though I know it's running. If I go into the phone's Settings -> Applications -> Running Services, I can see it running there.
I read in the documentation somewhere that calling startService on a service that is already running should be ignored. But that isn't the case as I can see in the debugger that both OnCreate and OnStart are being called.
It is important that I do not create a new service each time because the background service may be in the middle of serving a file. The activity does not need to do any communication with the service - only start it if it isn't running and kill it if the user hits a button.
Any idea on why my service is not showing up in the getRunningServices list?
Step #1: Add static boolean isRunning=false to your service.
Step #2: Set isRunning to true in onCreate() of the service.
Step #3: Set isRunning to false in onDestroy() of the service.
Step #4: Examine isRunning to see if the service is running.
I read in the documentation somewhere that calling startService on a service that is already running should be ignored. But that isn't the case as I can see in the debugger that both OnCreate and OnStart are being called.
I am very confident that onCreate() is not called when startService() is invoked on a running service. onStartCommand() (and, hence, onStart() for older services) will be called for every startService() call.
It is important that I do not create a new service each time
Services are natural singletons. There will be precisely 0 or 1 copies of the service in memory. There will never be 2 or more.
Actually, my service is now showing up in the list of services. I'm now thinking that maybe the service name wasn't registered until after restarting the phone, because I didn't make any changes but everything is working now after restarting.