如何查看后台服务是否正在运行?
我想要一个切换服务状态的Android活动——它让我打开它,如果它是关闭的,如果它是关闭的。
如何查看后台服务是否正在运行?
我想要一个切换服务状态的Android活动——它让我打开它,如果它是关闭的,如果它是关闭的。
当前回答
简单使用绑定不创建自动查看ps和更新…
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);
例子:
Intent bindIntent = new Intent(context, Class<Service>);
boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);
为什么不使用呢?getRunningServices ()
List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.
注意:此方法仅用于调试或实现服务管理类型的用户界面。
附注:android文档具有误导性,我已经在谷歌跟踪器上打开了一个问题,以消除任何疑问:
https://issuetracker.google.com/issues/68908332
正如我们所看到的,绑定服务实际上通过ActivityManager绑定器通过服务缓存绑定器调用了一个事务-我不能跟踪哪个服务负责绑定,但正如我们所看到的,绑定的结果是:
int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;
通过装订本进行交易:
ServiceManager.getService("activity");
下一个:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
这是在ActivityThread中通过:
public final void bindApplication(...) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
在ActivityManagerService的method中调用:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(... , getCommonServicesLocked(),...)
然后:
private HashMap<String, IBinder> getCommonServicesLocked() {
但没有“活动”,只有窗口包和报警。
所以我们需要返回调用:
return getIServiceManager().getService(name);
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
这使呼叫通过:
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
这就导致:
BinderInternal.getContextObject()
这是本地方法....
/**
* 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();
我现在没有时间去挖掘c,所以在我解析rest call之前,我暂停了我的回答。
但是检查服务是否正在运行的最好方法是创建bind(如果没有创建bind,则服务不存在)-并通过bind查询服务的状态(在其状态上使用存储的内部标志)。
更新23.06.2018
我发现这些很有趣:
/**
* 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;
}
简而言之:)
“为已经绑定的服务提供绑定器。此方法是同步的,如果目标服务不存在,则不会启动该服务。”
(Intent service, String resolvedType) String callingPackage)抛出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;
}
*
其他回答
得到它!
你必须调用startService()为你的服务正确注册和传递BIND_AUTO_CREATE是不够的。
Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);
现在是ServiceTools类:
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;
}
}
对于kotlin,可以使用下面的代码。
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
}
同样,如果使用pending intent(例如使用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);
}
CODE是一个常量,您在类中私有地定义它,以标识与您的服务相关联的挂起意图。
如果你有一个多模块的应用程序,你想知道服务是否从一个模块运行,这取决于包含该服务的模块,你可以使用这个函数:
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)
}
}
MyService服务用法:
isServiceRunning(context, "MyService")
如果服务类名称更改而调用函数没有相应更改,则此函数可能无法正常工作。
你可以使用这个(我还没有尝试过,但我希望它能工作):
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();
}
如果已经有一个正在运行的服务,startService方法将返回ComponentName对象。如果不是,则返回null。
参见公共抽象ComponentName startService (Intent服务)。
这和检查不一样,因为它正在启动服务,所以你可以添加stopService(someIntent);按照规定。