如何查看后台服务是否正在运行?
我想要一个切换服务状态的Android活动——它让我打开它,如果它是关闭的,如果它是关闭的。
如何查看后台服务是否正在运行?
我想要一个切换服务状态的Android活动——它让我打开它,如果它是关闭的,如果它是关闭的。
当前回答
放轻松,伙计们……:)
我认为最合适的解决方案是在SharedPreferences中保存一个关于服务是否正在运行的键-值对。
逻辑是很直接的;在你的服务等级的任何理想职位;输入一个布尔值,作为服务是否正在运行的标志。然后在应用程序中任意位置读取这个值。
我在我的应用程序中使用的示例代码如下:
在我的服务类(音频流服务),我执行以下代码时,服务是起;
private void updatePlayerStatus(boolean isRadioPlaying)
{
SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(getString(R.string.str_shared_file_radio_status_key), isRadioPlaying);
editor.commit();
}
然后在我的应用程序的任何活动中,我在以下代码的帮助下检查服务的状态;
private boolean isRadioRunning() {
SharedPreferences sharedPref = this.getSharedPreferences(getString(R.string.str_shared_file_name), Context.MODE_PRIVATE);
return sharedPref.getBoolean(getString(R.string.str_shared_file_radio_status_key), false);
}
没有特殊权限,没有循环……简单的方法,干净的解决方案:)
如果您需要更多的信息,请参考链接
希望这能有所帮助。
其他回答
简单使用绑定不创建自动查看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;
}
*
在Kotlin课上,geekQ的反应。由于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
}
调用
isMyServiceRunning(NewService::class.java)
如果服务属于另一个进程或APK,则使用基于ActivityManager的解决方案。
如果您可以访问它的源,只需使用基于静态字段的解决方案。但是我建议使用Date对象来代替布尔值。在服务运行时,只需将其值更新为'now',当它完成时将其设置为null。从活动中,您可以检查它是否为空或日期太旧,这将意味着它没有运行。
您还可以从您的服务发送广播通知,表明正在运行以及进一步的信息,如进度。
/**
* 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;
}
下面是一个优雅的技巧,涵盖了所有的假设。这只适用于本地服务。
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;
}
}
然后是:
if(AService.isServiceCreated()){
...
}else{
startService(...);
}