Hidden constructor called more than once per process - android

I got this error in my logcat
TelephonyManager : Hidden constructor called more than once per process!
And my PhoneListener is not working
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.e("state", "idle");
break;
case TelephonyManager.DATA_CONNECTED:
Log.e("state", "connected");
break;
}
};
};
telManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telManager.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);
It won't print out my log.

From the source code i got this:
/** Provides access to information about the telephony services on the device. Applications can use the methods in this class to determine telephony services and states, as well as to access some types of subscriber information. Applications can also register a listener to receive notification of telephony state changes.
You do not instantiate this class directly; instead, you retrieve a reference to an instance through {#link android.content.Context#getSystemService Context.getSystemService(Context.TELEPHONY_SERVICE)}. *
Note that access to some telephony information is permission-protected. Your application cannot access the protected * information unless it has the appropriate permissions declared in its manifest file. Where permissions apply, they are noted in the the methods through which you access the protected information. **/
public class TelephonyManager {
private static final String TAG = "TelephonyManager";
private static Context sContext;
private static ITelephonyRegistry sRegistry;
/** #hide */
public TelephonyManager(Context context) {
context = context.getApplicationContext();
if (sContext == null) {
sContext = context;
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
} else if (sContext != context) {
Log.e(TAG, "Hidden constructor called more than once per process!");
Log.e(TAG, "Original: " + sContext.getPackageName() + ", new: " +
context.getPackageName());
}
}
Are you creating multiple instance of TelephonyManger from different context? If so then the Error Log will show as the context is static.

Related

How to acces getSystemService in Application class

I want to access the TELEPHONY_SERVICE system service in the Application class, but my app crashes when I run it.
public class SimpleDhtApplication extends Application {
TelephonyManager tel = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
String portStr = tel.getLine1Number().substring(tel.getLine1Number().length() -4);
final String myPort = String.valueOf((Integer.parseInt(portStr) * 2));
}
I think I am not accessing the context correctly, can somebody help!
Override the onCreate method of the Application class first. Within the onCreate, put the code you have so it would look like:
public class SimpleDhtApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
TelephonyManager tel = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
String portStr = tel.getLine1Number().substring(tel.getLine1Number().length() -4);
final String myPort = String.valueOf((Integer.parseInt(portStr) * 2));
}
}
Update: Watch out for tel.getLine1Number(); it may return null as explained here.

Using Resources in Exceptions

I have an app that uses custom Exceptions, such as this:
public class SomeException extends Exception{
private int iCode;
private String iMessage;
public SomeException(){
iCode = 201;
iMessage = **//Get the localized string R.string.error_201??**
}
#Override
public String getMessage() {
return iMessage;
}
#Override
public int getCode() {
return iCode;
}
}
Obviously, I want lo localize the error message. I have possible solutions but non of them satisfy me.
1) Pass "Context" to the constructor, and do ctx.getString(R.string.error_201)
--> Fail, as this Exceptions are sometimes thrown from MODEL classes, so they don't have a Context
2) Pass "Context" when retriveing the message in getMessage() function,
--> Fail, It's necesary to override the super method, to work as all other Exceptions.
Solution I have now: All activities in my app have this onCreate:
public void onCreate(...){
Utils.RESOURCES = getResources();
...
}
Very dirty code... I don't like the solution. My question is then,: is there a way to access the resources without the Context? And most important, How would an application such as mine solve this problem?
What about
public class MyException extends Exception {
private int iCode;
public MyException(int code) {
this.iCode = code;
}
#Override
public String getMessage() {
return "MyException code " + String.valueOf(iCode);
}
public String getLocalizedMessage(Context ctx) {
String message;
if (iCode == 201)
message = ctx.getString(R.string.error_201);
else if (iCode == 202)
message = ctx.getString(R.string.error_202);
// ...
}
}
Even if there was way to access context in different way, you should not do it. If you need to emit exceptions where you cannot pass Context, you should be able to access context before you display such error. I cannot see reason why you should create localized error messages from constructor. You can log to logcat not localized versions if you need. And where you want to display something in UI, you should have context at hand.
You can access only system wide resources without Context.
You need a Context, so I would suggest You to get it as soon as possible, and make it available through a static method or variable. You do the same thing in every Activity, but there is a cleaner method. You should make a custom Application, and override its onCreate() to make the resources public:
public class App extends Application {
private static Resources myResources;
#Override
public void onCreate() {
myResources = getBaseContext().getResources();
super.onCreate();
}
public static Resources getMyResources(){
return myResources;
}
}
The other thing you have to do is to set the Application in your manifest:
<application
android:name="{your_package}.App"
...
Now you can access the resources in all of your Activity without any preparation. Your custom Exception class could also use the externalized resources.

What does "Hidden constructor called more than once per process" mean?

In my LogCat while debugging my app, I often get:
E/TelephonyManager(5382): Hidden constructor called more than once per process!
I've been Googling around a bit, and while I noticed other mentions of the error (in other logs), I cannot identify what it means.
So what is this error? Why am I getting it? And what is its significance?
This is from the Android source code:
/**
* Provides access to information about the telephony services on
* the device. Applications can use the methods in this class to
* determine telephony services and states, as well as to access some
* types of subscriber information. Applications can also register
* a listener to receive notification of telephony state changes.
*
* You do not instantiate this class directly; instead, you retrieve
* a reference to an instance through
* {#link android.content.Context#getSystemService
* Context.getSystemService(Context.TELEPHONY_SERVICE)}.
*
* Note that access to some telephony information is
* permission-protected. Your application cannot access the protected
* information unless it has the appropriate permissions declared in
* its manifest file. Where permissions apply, they are noted in the
* the methods through which you access the protected information.
*/
public class TelephonyManager {
private static final String TAG = "TelephonyManager";
private static Context sContext;
private static ITelephonyRegistry sRegistry;
/** #hide */
public TelephonyManager(Context context) {
context = context.getApplicationContext();
if (sContext == null) {
sContext = context;
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
} else if (sContext != context) {
Log.e(TAG, "Hidden constructor called more than once per process!");
Log.e(TAG, "Original: " + sContext.getPackageName() + ", new: " +
context.getPackageName());
}
}
The TelephonyManager seems to put the "Hidden constructor called more than once per process!" into the Log when your application calls the constructor more than once, as the message suggests. The constructor is called using the getSystemService as per the comments on the constructor.
Do you have more than one instance of:
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
or something similar in your code? This could possibly be causing the error.
EDIT: If it's not your code causing the message then it's the program running with PID 5382 I think.

How do I ask a Android service whether it's running? [duplicate]

How do I check if a background service is running?
I want an Android activity that toggles the state of the service -- it lets me turn it on if it is off and off if it is on.
I use the following from inside an activity:
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 I call it using:
isMyServiceRunning(MyService.class)
This works reliably, because it is based on the information about running services provided by the Android operating system through ActivityManager#getRunningServices.
All the approaches using onDestroy or onSometing events or Binders or static variables will not work reliably because as a developer you never know, when Android decides to kill your process or which of the mentioned callbacks are called or not. Please note the "killable" column in the lifecycle events table in the Android documentation.
I had the same problem not long ago. Since my service was local, I ended up simply using a static field in the service class to toggle state, as described by hackbod here
EDIT (for the record):
Here is the solution proposed by hackbod:
If your client and server code is part of the same .apk and you are
binding to the service with a concrete Intent (one that specifies the
exact service class), then you can simply have your service set a
global variable when it is running that your client can check.
We deliberately don't have an API to check whether a service is
running because, nearly without fail, when you want to do something
like that you end up with race conditions in your code.
Got it!
You MUST call startService() for your service to be properly registered and passing BIND_AUTO_CREATE will not suffice.
Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);
And now the ServiceTools class:
public class ServiceTools {
private static String LOG_TAG = ServiceTools.class.getName();
public static boolean isServiceRunning(String serviceClassName){
final ActivityManager activityManager = (ActivityManager)Application.getContext().getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (RunningServiceInfo runningServiceInfo : services) {
if (runningServiceInfo.service.getClassName().equals(serviceClassName)){
return true;
}
}
return false;
}
}
A small complement is:
My goal is to know wether a service is running without actualy running it if it is not running.
Calling bindService or calling an intent that can be caught by the service is not a good idea then as it will start the service if it is not running.
So, as miracle2k suggested, the best is to have a static field in the service class to know whether the service has been started or not.
To make it even cleaner, I suggest to transform the service in a singleton with a very very lazy fetching: that is, there is no instantiation at all of the singleton instance through static methods. The static getInstance method of your service/singleton just returns the instance of the singleton if it has been created. But it doesn't actualy start or instanciate the singleton itself. The service is only started through normal service start methods.
It would then be even cleaner to modify the singleton design pattern to rename the confusing getInstance method into something like the isInstanceCreated() : boolean method.
The code will look like:
public class MyService extends Service
{
private static MyService instance = null;
public static boolean isInstanceCreated() {
return instance != null;
}//met
#Override
public void onCreate()
{
instance = this;
....
}//met
#Override
public void onDestroy()
{
instance = null;
...
}//met
}//class
This solution is elegant, but it is only relevant if you have access to the service class and only for classes iside the app/package of the service. If your classes are outside of the service app/package then you could query the ActivityManager with limitations underlined by Pieter-Jan Van Robays.
You can use this (I didn't try this yet, but I hope this works):
if(startService(someIntent) != null) {
Toast.makeText(getBaseContext(), "Service is already running", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getBaseContext(), "There is no service running, starting service..", Toast.LENGTH_SHORT).show();
}
The startService method returns a ComponentName object if there is an already running service. If not, null will be returned.
See public abstract ComponentName startService (Intent service).
This is not like checking I think, because it's starting the service, so you can add stopService(someIntent); under the code.
/**
* Check if the service is Running
* #param serviceClass the class of the Service
*
* #return true if the service is running otherwise false
*/
public boolean checkServiceRunning(Class<?> serviceClass){
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
{
if (serviceClass.getName().equals(service.service.getClassName()))
{
return true;
}
}
return false;
}
An extract from Android docs:
Like sendBroadcast(Intent), but if there are any receivers for
the Intent this function will block and immediately dispatch them
before returning.
Think of this hack as "pinging" the Service. Since we can broadcast synchronously, we can broadcast and get a result synchronously, on the UI thread.
Service
#Override
public void onCreate() {
LocalBroadcastManager
.getInstance(this)
.registerReceiver(new ServiceEchoReceiver(), new IntentFilter("ping"));
//do not forget to deregister the receiver when the service is destroyed to avoid
//any potential memory leaks
}
private class ServiceEchoReceiver extends BroadcastReceiver {
public void onReceive (Context context, Intent intent) {
LocalBroadcastManager
.getInstance(this)
.sendBroadcastSync(new Intent("pong"));
}
}
Activity
bool serviceRunning = false;
protected void onCreate (Bundle savedInstanceState){
LocalBroadcastManager.getInstance(this).registerReceiver(pong, new IntentFilter("pong"));
LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("ping"));
if(!serviceRunning){
//run the service
}
}
private BroadcastReceiver pong = new BroadcastReceiver(){
public void onReceive (Context context, Intent intent) {
serviceRunning = true;
}
}
The winner in many applications is, of course, a static boolean field on the service that is set to true in Service.onCreate() and to false in Service.onDestroy() because it's a lot simpler.
Another approach using kotlin. Inspired in other users answers
fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
return manager.getRunningServices(Integer.MAX_VALUE)
.any { it.service.className == serviceClass.name }
}
As kotlin extension
fun Context.isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
return manager.getRunningServices(Integer.MAX_VALUE)
.any { it.service.className == serviceClass.name }
}
Usage
context.isMyServiceRunning(MyService::class.java)
The proper way to check if a service is running is to simply ask it. Implement a BroadcastReceiver in your service that responds to pings from your activities. Register the BroadcastReceiver when the service starts, and unregister it when the service is destroyed. From your activity (or any component), send a local broadcast intent to the service and if it responds, you know it's running. Note the subtle difference between ACTION_PING and ACTION_PONG in the code below.
public class PingableService extends Service {
public static final String ACTION_PING = PingableService.class.getName() + ".PING";
public static final String ACTION_PONG = PingableService.class.getName() + ".PONG";
public int onStartCommand (Intent intent, int flags, int startId) {
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(ACTION_PING));
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy () {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
super.onDestroy();
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive (Context context, Intent intent) {
if (intent.getAction().equals(ACTION_PING)) {
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
manager.sendBroadcast(new Intent(ACTION_PONG));
}
}
};
}
public class MyActivity extends Activity {
private boolean isSvcRunning = false;
#Override
protected void onStart() {
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
manager.registerReceiver(mReceiver, new IntentFilter(PingableService.ACTION_PONG));
// the service will respond to this broadcast only if it's running
manager.sendBroadcast(new Intent(PingableService.ACTION_PING));
super.onStart();
}
#Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
super.onStop();
}
protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive (Context context, Intent intent) {
// here you receive the response from the service
if (intent.getAction().equals(PingableService.ACTION_PONG)) {
isSvcRunning = true;
}
}
};
}
I have slightly modified one of the solutions presented above, but passing the class instead of a generic string name, in order to be sure to compare strings coming out from the same method class.getName()
public class ServiceTools {
private static String LOG_TAG = ServiceTools.class.getName();
public static boolean isServiceRunning(Context context,Class<?> serviceClass){
final ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (RunningServiceInfo runningServiceInfo : services) {
Log.d(Constants.TAG, String.format("Service:%s", runningServiceInfo.service.getClassName()));
if (runningServiceInfo.service.getClassName().equals(serviceClass.getName())){
return true;
}
}
return false;
}
}
and then
Boolean isServiceRunning = ServiceTools.isServiceRunning(
MainActivity.this.getApplicationContext(),
BackgroundIntentService.class);
I just want to add a note to the answer by #Snicolas. The following steps can be used to check stop service with/without calling onDestroy().
onDestroy() called: Go to Settings -> Application -> Running Services -> Select and stop your service.
onDestroy() not Called: Go to Settings -> Application -> Manage Applications -> Select and "Force Stop" your application in which your service is running. However, as your application is stopped here, so definitely the service instances will also be stopped.
Finally, I would like to mention that the approach mentioned there using a static variable in singleton class is working for me.
First of all you shouldn't reach the service by using the ActivityManager. (Discussed here)
Services can run on their own, be bound to an Activity or both. The way to check in an Activity if your Service is running or not is by making an interface (that extends Binder) where you declare methods that both, the Activity and the Service, understand. You can do this by making your own Interface where you declare for example "isServiceRunning()".
You can then bind your Activity to your Service, run the method isServiceRunning(), the Service will check for itself if it is running or not and returns a boolean to your Activity.
You can also use this method to stop your Service or interact with it in another way.
onDestroy isn't always called in the service so this is useless!
For example: Just run the app again with one change from Eclipse. The application is forcefully exited using SIG: 9.
Again, another alternative that people might find cleaner if they use pending intents (for instance with the AlarmManager:
public static boolean isRunning(Class<? extends Service> serviceClass) {
final Intent intent = new Intent(context, serviceClass);
return (PendingIntent.getService(context, CODE, intent, PendingIntent.FLAG_NO_CREATE) != null);
}
Where CODE is a constant that you define privately in your class to identify the pending intents associated to your service.
Below is an elegant hack that covers all the Ifs. This is for local services only.
public final class AService extends Service {
private static AService mInstance = null;
public static boolean isServiceCreated() {
try {
// If instance was not cleared but the service was destroyed an Exception will be thrown
return mInstance != null && mInstance.ping();
} catch (NullPointerException e) {
// destroyed/not-started
return false;
}
}
/**
* Simply returns true. If the service is still active, this method will be accessible.
* #return
*/
private boolean ping() {
return true;
}
#Override
public void onCreate() {
mInstance = this;
}
#Override
public void onDestroy() {
mInstance = null;
}
}
And then later on:
if(AService.isServiceCreated()){
...
}else{
startService(...);
}
Xamarin C# version:
private bool isMyServiceRunning(System.Type cls)
{
ActivityManager manager = (ActivityManager)GetSystemService(Context.ActivityService);
foreach (var service in manager.GetRunningServices(int.MaxValue)) {
if (service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName)) {
return true;
}
}
return false;
}
For the use-case given here we may simply make use of the stopService() method's return value. It returns true if there exists the specified service and it is killed. Else it returns false. So you may restart the service if the result is false else it is assured that the current service has been stopped. :) It would be better if you have a look at this.
The response of geekQ but in Kotlin class. Thanks geekQ
fun isMyServiceRunning(serviceClass : Class<*> ) : Boolean{
var manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.name.equals(service.service.className)) {
return true
}
}
return false
}
The call
isMyServiceRunning(NewService::class.java)
In your Service Sub-Class Use a Static Boolean to get the state of the Service as demonstrated below.
MyService.kt
class MyService : Service() {
override fun onCreate() {
super.onCreate()
isServiceStarted = true
}
override fun onDestroy() {
super.onDestroy()
isServiceStarted = false
}
companion object {
var isServiceStarted = false
}
}
MainActivity.kt
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val serviceStarted = FileObserverService.isServiceStarted
if (!serviceStarted) {
val startFileObserverService = Intent(this, FileObserverService::class.java)
ContextCompat.startForegroundService(this, startFileObserverService)
}
}
}
In kotlin you can add boolean variable in companion object and check its value from any class you want:
companion object{
var isRuning = false
}
Change it value when service is created and destroyed
override fun onCreate() {
super.onCreate()
isRuning = true
}
override fun onDestroy() {
super.onDestroy()
isRuning = false
}
For kotlin, you can use the below code.
fun isMyServiceRunning(calssObj: Class<SERVICE_CALL_NAME>): Boolean {
val manager = requireActivity().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (calssObj.getName().equals(service.service.getClassName())) {
return true
}
}
return false
}
Inside TheServiceClass define:
public static Boolean serviceRunning = false;
Then In onStartCommand(...)
public int onStartCommand(Intent intent, int flags, int startId) {
serviceRunning = true;
...
}
#Override
public void onDestroy()
{
serviceRunning = false;
}
Then, call if(TheServiceClass.serviceRunning == true) from any class.
simple use bind with don't create auto - see ps. and update...
public abstract class Context {
...
/*
* #return {true} If you have successfully bound to the service,
* {false} is returned if the connection is not made
* so you will not receive the service object.
*/
public abstract boolean bindService(#RequiresPermission Intent service,
#NonNull ServiceConnection conn, #BindServiceFlags int flags);
example :
Intent bindIntent = new Intent(context, Class<Service>);
boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);
why not using? getRunningServices()
List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.
Note: this method is only intended for debugging or implementing service management type user interfaces.
ps. android documentation is misleading i have opened an issue on google tracker to eliminate any doubts:
https://issuetracker.google.com/issues/68908332
as we can see bind service actually invokes a transaction via ActivityManager binder through Service cache binders - i dint track which service is responsible for binding but as we can see the result for bind is:
int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;
transaction is made through binder:
ServiceManager.getService("activity");
next:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
this is set in ActivityThread via:
public final void bindApplication(...) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
this is called in ActivityManagerService in method:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(... , getCommonServicesLocked(),...)
then:
private HashMap<String, IBinder> getCommonServicesLocked() {
but there is no "activity" only window package and alarm..
so we need get back to call:
return getIServiceManager().getService(name);
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
this makes call through:
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
which leads to :
BinderInternal.getContextObject()
and this is native method....
/**
* Return the global "context object" of the system. This is usually
* an implementation of IServiceManager, which you can use to find
* other services.
*/
public static final native IBinder getContextObject();
i don't have time now to dug in c so until i dissect rest call i suspend my answer.
but best way for check if service is running is to create bind (if bind is not created service not exist) - and query the service about its state through the bind (using stored internal flag on it state).
update 23.06.2018
i found those interesting:
/**
* Provide a binder to an already-bound service. This method is synchronous
* and will not start the target service if it is not present, so it is safe
* to call from {#link #onReceive}.
*
* For peekService() to return a non null {#link android.os.IBinder} interface
* the service must have published it before. In other words some component
* must have called {#link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
*
* #param myContext The Context that had been passed to {#link #onReceive(Context, Intent)}
* #param service Identifies the already-bound service you wish to use. See
* {#link android.content.Context#bindService(Intent, ServiceConnection, int)}
* for more information.
*/
public IBinder peekService(Context myContext, Intent service) {
IActivityManager am = ActivityManager.getService();
IBinder binder = null;
try {
service.prepareToLeaveProcess(myContext);
binder = am.peekService(service, service.resolveTypeIfNeeded(
myContext.getContentResolver()), myContext.getOpPackageName());
} catch (RemoteException e) {
}
return binder;
}
in short :)
"Provide a binder to an already-bound service. This method is synchronous and will not start the target service if it is not present."
public IBinder peekService(Intent service, String resolvedType,
String callingPackage) throws RemoteException;
*
public static IBinder peekService(IBinder remote, Intent service, String resolvedType)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken("android.app.IActivityManager");
service.writeToParcel(data, 0);
data.writeString(resolvedType);
remote.transact(android.os.IBinder.FIRST_CALL_TRANSACTION+84, data, reply, 0);
reply.readException();
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
*
There can be several services with the same class name.
I've just created two apps. The package name of the first app is com.example.mock. I created a subpackage called lorem in the app and a service called Mock2Service. So its fully qualified name is com.example.mock.lorem.Mock2Service.
Then I created the second app and a service called Mock2Service. The package name of the second app is com.example.mock.lorem. The fully qualified name of the service is com.example.mock.lorem.Mock2Service, too.
Here is my logcat output.
03-27 12:02:19.985: D/TAG(32155): Mock-01: com.example.mock.lorem.Mock2Service
03-27 12:02:33.755: D/TAG(32277): Mock-02: com.example.mock.lorem.Mock2Service
A better idea is to compare ComponentName instances because equals() of ComponentName compares both package names and class names. And there can't be two apps with the same package name installed on a device.
The equals() method of ComponentName.
#Override
public boolean equals(Object obj) {
try {
if (obj != null) {
ComponentName other = (ComponentName)obj;
// Note: no null checks, because mPackage and mClass can
// never be null.
return mPackage.equals(other.mPackage)
&& mClass.equals(other.mClass);
}
} catch (ClassCastException e) {
}
return false;
}
ComponentName
Please use this code.
if (isMyServiceRunning(MainActivity.this, xyzService.class)) { // Service class name
// Service running
} else {
// Service Stop
}
public static boolean isMyServiceRunning(Activity activity, Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
If you have a multi-module application and you want to know that service is running or not from a module that is not depends on the module that contains the service, you can use this function:
fun isServiceRunning(context: Context, serviceClassName: String): Boolean {
val manager = ContextCompat.getSystemService(
context,
ActivityManager::class.java
) ?: return false
return manager.getRunningServices(Integer.MAX_VALUE).any { serviceInfo ->
serviceInfo.service.shortClassName.contains(vpnServiceClassName)
}
}
Usage for MyService service:
isServiceRunning(context, "MyService")
This function may not work correctly if the service class name changes and the calling function does not change accordingly.
This applies more towards Intent Service debugging since they spawn a thread, but may work for regular services as well. I found this thread thanks to Binging
In my case, I played around with the debugger and found the thread view. It kind of looks like the bullet point icon in MS Word. Anyways, you don't have to be in debugger mode to use it. Click on the process and click on that button. Any Intent Services will show up while they are running, at least on the emulator.
If the service belongs to another process or APK use the solution based on the ActivityManager.
If you have access to its source, just use the solution based on a static field. But instead using a boolean I would suggest using a Date object. While the service is running, just update its value to 'now' and when it finishes set it to null. From the activity you can check if its null or the date is too old which will mean that it is not running.
You can also send broadcast notification from your service indicating that is running along further info like progress.
My kotlin conversion of the ActivityManager::getRunningServices based answers. Put this function in an activity-
private fun isMyServiceRunning(serviceClass: Class<out Service>) =
(getSystemService(ACTIVITY_SERVICE) as ActivityManager)
.getRunningServices(Int.MAX_VALUE)
?.map { it.service.className }
?.contains(serviceClass.name) ?: false
Since Android 8 (or Oreo), API getRunningServices is deprecated.
Of course your can use #SuppressWarnings("deprecation") to get rid of the warning.
Here is how to do without getRunninngServices if your service does not need to have more than one instance: use the singleton pattern.
public class MyMusicService extends Service {
private static MyMusicService instance = null;
public static boolean isMyMusicServiceRunning() {
return instance != null;
}
Then you can call the MyMusicService.isMyMusicServiceRunning from your activities or elsewhere.

How to check if a service is running on Android?

How do I check if a background service is running?
I want an Android activity that toggles the state of the service -- it lets me turn it on if it is off and off if it is on.
I use the following from inside an activity:
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 I call it using:
isMyServiceRunning(MyService.class)
This works reliably, because it is based on the information about running services provided by the Android operating system through ActivityManager#getRunningServices.
All the approaches using onDestroy or onSometing events or Binders or static variables will not work reliably because as a developer you never know, when Android decides to kill your process or which of the mentioned callbacks are called or not. Please note the "killable" column in the lifecycle events table in the Android documentation.
I had the same problem not long ago. Since my service was local, I ended up simply using a static field in the service class to toggle state, as described by hackbod here
EDIT (for the record):
Here is the solution proposed by hackbod:
If your client and server code is part of the same .apk and you are
binding to the service with a concrete Intent (one that specifies the
exact service class), then you can simply have your service set a
global variable when it is running that your client can check.
We deliberately don't have an API to check whether a service is
running because, nearly without fail, when you want to do something
like that you end up with race conditions in your code.
Got it!
You MUST call startService() for your service to be properly registered and passing BIND_AUTO_CREATE will not suffice.
Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);
And now the ServiceTools class:
public class ServiceTools {
private static String LOG_TAG = ServiceTools.class.getName();
public static boolean isServiceRunning(String serviceClassName){
final ActivityManager activityManager = (ActivityManager)Application.getContext().getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (RunningServiceInfo runningServiceInfo : services) {
if (runningServiceInfo.service.getClassName().equals(serviceClassName)){
return true;
}
}
return false;
}
}
A small complement is:
My goal is to know wether a service is running without actualy running it if it is not running.
Calling bindService or calling an intent that can be caught by the service is not a good idea then as it will start the service if it is not running.
So, as miracle2k suggested, the best is to have a static field in the service class to know whether the service has been started or not.
To make it even cleaner, I suggest to transform the service in a singleton with a very very lazy fetching: that is, there is no instantiation at all of the singleton instance through static methods. The static getInstance method of your service/singleton just returns the instance of the singleton if it has been created. But it doesn't actualy start or instanciate the singleton itself. The service is only started through normal service start methods.
It would then be even cleaner to modify the singleton design pattern to rename the confusing getInstance method into something like the isInstanceCreated() : boolean method.
The code will look like:
public class MyService extends Service
{
private static MyService instance = null;
public static boolean isInstanceCreated() {
return instance != null;
}//met
#Override
public void onCreate()
{
instance = this;
....
}//met
#Override
public void onDestroy()
{
instance = null;
...
}//met
}//class
This solution is elegant, but it is only relevant if you have access to the service class and only for classes iside the app/package of the service. If your classes are outside of the service app/package then you could query the ActivityManager with limitations underlined by Pieter-Jan Van Robays.
You can use this (I didn't try this yet, but I hope this works):
if(startService(someIntent) != null) {
Toast.makeText(getBaseContext(), "Service is already running", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(getBaseContext(), "There is no service running, starting service..", Toast.LENGTH_SHORT).show();
}
The startService method returns a ComponentName object if there is an already running service. If not, null will be returned.
See public abstract ComponentName startService (Intent service).
This is not like checking I think, because it's starting the service, so you can add stopService(someIntent); under the code.
/**
* Check if the service is Running
* #param serviceClass the class of the Service
*
* #return true if the service is running otherwise false
*/
public boolean checkServiceRunning(Class<?> serviceClass){
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
{
if (serviceClass.getName().equals(service.service.getClassName()))
{
return true;
}
}
return false;
}
An extract from Android docs:
Like sendBroadcast(Intent), but if there are any receivers for
the Intent this function will block and immediately dispatch them
before returning.
Think of this hack as "pinging" the Service. Since we can broadcast synchronously, we can broadcast and get a result synchronously, on the UI thread.
Service
#Override
public void onCreate() {
LocalBroadcastManager
.getInstance(this)
.registerReceiver(new ServiceEchoReceiver(), new IntentFilter("ping"));
//do not forget to deregister the receiver when the service is destroyed to avoid
//any potential memory leaks
}
private class ServiceEchoReceiver extends BroadcastReceiver {
public void onReceive (Context context, Intent intent) {
LocalBroadcastManager
.getInstance(this)
.sendBroadcastSync(new Intent("pong"));
}
}
Activity
bool serviceRunning = false;
protected void onCreate (Bundle savedInstanceState){
LocalBroadcastManager.getInstance(this).registerReceiver(pong, new IntentFilter("pong"));
LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("ping"));
if(!serviceRunning){
//run the service
}
}
private BroadcastReceiver pong = new BroadcastReceiver(){
public void onReceive (Context context, Intent intent) {
serviceRunning = true;
}
}
The winner in many applications is, of course, a static boolean field on the service that is set to true in Service.onCreate() and to false in Service.onDestroy() because it's a lot simpler.
Another approach using kotlin. Inspired in other users answers
fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
return manager.getRunningServices(Integer.MAX_VALUE)
.any { it.service.className == serviceClass.name }
}
As kotlin extension
fun Context.isMyServiceRunning(serviceClass: Class<*>): Boolean {
val manager = this.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
return manager.getRunningServices(Integer.MAX_VALUE)
.any { it.service.className == serviceClass.name }
}
Usage
context.isMyServiceRunning(MyService::class.java)
The proper way to check if a service is running is to simply ask it. Implement a BroadcastReceiver in your service that responds to pings from your activities. Register the BroadcastReceiver when the service starts, and unregister it when the service is destroyed. From your activity (or any component), send a local broadcast intent to the service and if it responds, you know it's running. Note the subtle difference between ACTION_PING and ACTION_PONG in the code below.
public class PingableService extends Service {
public static final String ACTION_PING = PingableService.class.getName() + ".PING";
public static final String ACTION_PONG = PingableService.class.getName() + ".PONG";
public int onStartCommand (Intent intent, int flags, int startId) {
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(ACTION_PING));
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy () {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
super.onDestroy();
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive (Context context, Intent intent) {
if (intent.getAction().equals(ACTION_PING)) {
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
manager.sendBroadcast(new Intent(ACTION_PONG));
}
}
};
}
public class MyActivity extends Activity {
private boolean isSvcRunning = false;
#Override
protected void onStart() {
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getApplicationContext());
manager.registerReceiver(mReceiver, new IntentFilter(PingableService.ACTION_PONG));
// the service will respond to this broadcast only if it's running
manager.sendBroadcast(new Intent(PingableService.ACTION_PING));
super.onStart();
}
#Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
super.onStop();
}
protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive (Context context, Intent intent) {
// here you receive the response from the service
if (intent.getAction().equals(PingableService.ACTION_PONG)) {
isSvcRunning = true;
}
}
};
}
I have slightly modified one of the solutions presented above, but passing the class instead of a generic string name, in order to be sure to compare strings coming out from the same method class.getName()
public class ServiceTools {
private static String LOG_TAG = ServiceTools.class.getName();
public static boolean isServiceRunning(Context context,Class<?> serviceClass){
final ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (RunningServiceInfo runningServiceInfo : services) {
Log.d(Constants.TAG, String.format("Service:%s", runningServiceInfo.service.getClassName()));
if (runningServiceInfo.service.getClassName().equals(serviceClass.getName())){
return true;
}
}
return false;
}
}
and then
Boolean isServiceRunning = ServiceTools.isServiceRunning(
MainActivity.this.getApplicationContext(),
BackgroundIntentService.class);
I just want to add a note to the answer by #Snicolas. The following steps can be used to check stop service with/without calling onDestroy().
onDestroy() called: Go to Settings -> Application -> Running Services -> Select and stop your service.
onDestroy() not Called: Go to Settings -> Application -> Manage Applications -> Select and "Force Stop" your application in which your service is running. However, as your application is stopped here, so definitely the service instances will also be stopped.
Finally, I would like to mention that the approach mentioned there using a static variable in singleton class is working for me.
First of all you shouldn't reach the service by using the ActivityManager. (Discussed here)
Services can run on their own, be bound to an Activity or both. The way to check in an Activity if your Service is running or not is by making an interface (that extends Binder) where you declare methods that both, the Activity and the Service, understand. You can do this by making your own Interface where you declare for example "isServiceRunning()".
You can then bind your Activity to your Service, run the method isServiceRunning(), the Service will check for itself if it is running or not and returns a boolean to your Activity.
You can also use this method to stop your Service or interact with it in another way.
onDestroy isn't always called in the service so this is useless!
For example: Just run the app again with one change from Eclipse. The application is forcefully exited using SIG: 9.
Again, another alternative that people might find cleaner if they use pending intents (for instance with the AlarmManager:
public static boolean isRunning(Class<? extends Service> serviceClass) {
final Intent intent = new Intent(context, serviceClass);
return (PendingIntent.getService(context, CODE, intent, PendingIntent.FLAG_NO_CREATE) != null);
}
Where CODE is a constant that you define privately in your class to identify the pending intents associated to your service.
Below is an elegant hack that covers all the Ifs. This is for local services only.
public final class AService extends Service {
private static AService mInstance = null;
public static boolean isServiceCreated() {
try {
// If instance was not cleared but the service was destroyed an Exception will be thrown
return mInstance != null && mInstance.ping();
} catch (NullPointerException e) {
// destroyed/not-started
return false;
}
}
/**
* Simply returns true. If the service is still active, this method will be accessible.
* #return
*/
private boolean ping() {
return true;
}
#Override
public void onCreate() {
mInstance = this;
}
#Override
public void onDestroy() {
mInstance = null;
}
}
And then later on:
if(AService.isServiceCreated()){
...
}else{
startService(...);
}
Xamarin C# version:
private bool isMyServiceRunning(System.Type cls)
{
ActivityManager manager = (ActivityManager)GetSystemService(Context.ActivityService);
foreach (var service in manager.GetRunningServices(int.MaxValue)) {
if (service.Service.ClassName.Equals(Java.Lang.Class.FromType(cls).CanonicalName)) {
return true;
}
}
return false;
}
For the use-case given here we may simply make use of the stopService() method's return value. It returns true if there exists the specified service and it is killed. Else it returns false. So you may restart the service if the result is false else it is assured that the current service has been stopped. :) It would be better if you have a look at this.
The response of geekQ but in Kotlin class. Thanks geekQ
fun isMyServiceRunning(serviceClass : Class<*> ) : Boolean{
var manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.name.equals(service.service.className)) {
return true
}
}
return false
}
The call
isMyServiceRunning(NewService::class.java)
In your Service Sub-Class Use a Static Boolean to get the state of the Service as demonstrated below.
MyService.kt
class MyService : Service() {
override fun onCreate() {
super.onCreate()
isServiceStarted = true
}
override fun onDestroy() {
super.onDestroy()
isServiceStarted = false
}
companion object {
var isServiceStarted = false
}
}
MainActivity.kt
class MainActivity : AppCompatActivity(){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val serviceStarted = FileObserverService.isServiceStarted
if (!serviceStarted) {
val startFileObserverService = Intent(this, FileObserverService::class.java)
ContextCompat.startForegroundService(this, startFileObserverService)
}
}
}
In kotlin you can add boolean variable in companion object and check its value from any class you want:
companion object{
var isRuning = false
}
Change it value when service is created and destroyed
override fun onCreate() {
super.onCreate()
isRuning = true
}
override fun onDestroy() {
super.onDestroy()
isRuning = false
}
For kotlin, you can use the below code.
fun isMyServiceRunning(calssObj: Class<SERVICE_CALL_NAME>): Boolean {
val manager = requireActivity().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
if (calssObj.getName().equals(service.service.getClassName())) {
return true
}
}
return false
}
Inside TheServiceClass define:
public static Boolean serviceRunning = false;
Then In onStartCommand(...)
public int onStartCommand(Intent intent, int flags, int startId) {
serviceRunning = true;
...
}
#Override
public void onDestroy()
{
serviceRunning = false;
}
Then, call if(TheServiceClass.serviceRunning == true) from any class.
simple use bind with don't create auto - see ps. and update...
public abstract class Context {
...
/*
* #return {true} If you have successfully bound to the service,
* {false} is returned if the connection is not made
* so you will not receive the service object.
*/
public abstract boolean bindService(#RequiresPermission Intent service,
#NonNull ServiceConnection conn, #BindServiceFlags int flags);
example :
Intent bindIntent = new Intent(context, Class<Service>);
boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);
why not using? getRunningServices()
List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.
Note: this method is only intended for debugging or implementing service management type user interfaces.
ps. android documentation is misleading i have opened an issue on google tracker to eliminate any doubts:
https://issuetracker.google.com/issues/68908332
as we can see bind service actually invokes a transaction via ActivityManager binder through Service cache binders - i dint track which service is responsible for binding but as we can see the result for bind is:
int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;
transaction is made through binder:
ServiceManager.getService("activity");
next:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
this is set in ActivityThread via:
public final void bindApplication(...) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
this is called in ActivityManagerService in method:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(... , getCommonServicesLocked(),...)
then:
private HashMap<String, IBinder> getCommonServicesLocked() {
but there is no "activity" only window package and alarm..
so we need get back to call:
return getIServiceManager().getService(name);
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
this makes call through:
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
which leads to :
BinderInternal.getContextObject()
and this is native method....
/**
* Return the global "context object" of the system. This is usually
* an implementation of IServiceManager, which you can use to find
* other services.
*/
public static final native IBinder getContextObject();
i don't have time now to dug in c so until i dissect rest call i suspend my answer.
but best way for check if service is running is to create bind (if bind is not created service not exist) - and query the service about its state through the bind (using stored internal flag on it state).
update 23.06.2018
i found those interesting:
/**
* Provide a binder to an already-bound service. This method is synchronous
* and will not start the target service if it is not present, so it is safe
* to call from {#link #onReceive}.
*
* For peekService() to return a non null {#link android.os.IBinder} interface
* the service must have published it before. In other words some component
* must have called {#link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
*
* #param myContext The Context that had been passed to {#link #onReceive(Context, Intent)}
* #param service Identifies the already-bound service you wish to use. See
* {#link android.content.Context#bindService(Intent, ServiceConnection, int)}
* for more information.
*/
public IBinder peekService(Context myContext, Intent service) {
IActivityManager am = ActivityManager.getService();
IBinder binder = null;
try {
service.prepareToLeaveProcess(myContext);
binder = am.peekService(service, service.resolveTypeIfNeeded(
myContext.getContentResolver()), myContext.getOpPackageName());
} catch (RemoteException e) {
}
return binder;
}
in short :)
"Provide a binder to an already-bound service. This method is synchronous and will not start the target service if it is not present."
public IBinder peekService(Intent service, String resolvedType,
String callingPackage) throws RemoteException;
*
public static IBinder peekService(IBinder remote, Intent service, String resolvedType)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken("android.app.IActivityManager");
service.writeToParcel(data, 0);
data.writeString(resolvedType);
remote.transact(android.os.IBinder.FIRST_CALL_TRANSACTION+84, data, reply, 0);
reply.readException();
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
*
There can be several services with the same class name.
I've just created two apps. The package name of the first app is com.example.mock. I created a subpackage called lorem in the app and a service called Mock2Service. So its fully qualified name is com.example.mock.lorem.Mock2Service.
Then I created the second app and a service called Mock2Service. The package name of the second app is com.example.mock.lorem. The fully qualified name of the service is com.example.mock.lorem.Mock2Service, too.
Here is my logcat output.
03-27 12:02:19.985: D/TAG(32155): Mock-01: com.example.mock.lorem.Mock2Service
03-27 12:02:33.755: D/TAG(32277): Mock-02: com.example.mock.lorem.Mock2Service
A better idea is to compare ComponentName instances because equals() of ComponentName compares both package names and class names. And there can't be two apps with the same package name installed on a device.
The equals() method of ComponentName.
#Override
public boolean equals(Object obj) {
try {
if (obj != null) {
ComponentName other = (ComponentName)obj;
// Note: no null checks, because mPackage and mClass can
// never be null.
return mPackage.equals(other.mPackage)
&& mClass.equals(other.mClass);
}
} catch (ClassCastException e) {
}
return false;
}
ComponentName
Please use this code.
if (isMyServiceRunning(MainActivity.this, xyzService.class)) { // Service class name
// Service running
} else {
// Service Stop
}
public static boolean isMyServiceRunning(Activity activity, Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
If you have a multi-module application and you want to know that service is running or not from a module that is not depends on the module that contains the service, you can use this function:
fun isServiceRunning(context: Context, serviceClassName: String): Boolean {
val manager = ContextCompat.getSystemService(
context,
ActivityManager::class.java
) ?: return false
return manager.getRunningServices(Integer.MAX_VALUE).any { serviceInfo ->
serviceInfo.service.shortClassName.contains(vpnServiceClassName)
}
}
Usage for MyService service:
isServiceRunning(context, "MyService")
This function may not work correctly if the service class name changes and the calling function does not change accordingly.
This applies more towards Intent Service debugging since they spawn a thread, but may work for regular services as well. I found this thread thanks to Binging
In my case, I played around with the debugger and found the thread view. It kind of looks like the bullet point icon in MS Word. Anyways, you don't have to be in debugger mode to use it. Click on the process and click on that button. Any Intent Services will show up while they are running, at least on the emulator.
If the service belongs to another process or APK use the solution based on the ActivityManager.
If you have access to its source, just use the solution based on a static field. But instead using a boolean I would suggest using a Date object. While the service is running, just update its value to 'now' and when it finishes set it to null. From the activity you can check if its null or the date is too old which will mean that it is not running.
You can also send broadcast notification from your service indicating that is running along further info like progress.
My kotlin conversion of the ActivityManager::getRunningServices based answers. Put this function in an activity-
private fun isMyServiceRunning(serviceClass: Class<out Service>) =
(getSystemService(ACTIVITY_SERVICE) as ActivityManager)
.getRunningServices(Int.MAX_VALUE)
?.map { it.service.className }
?.contains(serviceClass.name) ?: false
Since Android 8 (or Oreo), API getRunningServices is deprecated.
Of course your can use #SuppressWarnings("deprecation") to get rid of the warning.
Here is how to do without getRunninngServices if your service does not need to have more than one instance: use the singleton pattern.
public class MyMusicService extends Service {
private static MyMusicService instance = null;
public static boolean isMyMusicServiceRunning() {
return instance != null;
}
Then you can call the MyMusicService.isMyMusicServiceRunning from your activities or elsewhere.

Categories

Resources