簡體   English   中英

如何查看服務是否在Android上運行?

[英]How to check if a service is running on Android?

如何檢查后台服務是否正在運行?

我想要一個切換服務的 state 的 Android 活動——它讓我在它關閉時打開它,在它打開時關閉它。

我在活動中使用以下內容:

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;
}

我稱之為:

isMyServiceRunning(MyService.class)

這工作可靠,因為它基於 Android 操作系統通過ActivityManager#getRunningServices提供的有關運行服務的信息。

所有使用 onDestroy 或 onSometing 事件或 Binders 或靜態變量的方法都無法可靠地工作,因為作為開發人員,您永遠不知道 Android 何時決定終止您的進程或調用或不調用提到的哪些回調。 請注意 Android 文檔中生命周期事件表中的“killable”列。

不久前我遇到了同樣的問題。 由於我的服務是本地的,我最終只是使用服務類中的靜態字段來切換狀態,如 hackbod here 所述

編輯(記錄):

這是hackbod提出的解決方案:

如果您的客戶端和服務器代碼是同一個 .apk 的一部分,並且您使用具體的 Intent(指定確切的服務類)綁定到服務,那么您可以簡單地讓您的服務在運行時設置一個全局變量您的客戶可以檢查。

我們故意沒有 API 來檢查服務是否正在運行,因為幾乎沒有失敗,當您想要做類似的事情時,您最終會在代碼中遇到競爭條件。

知道了!

必須調用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;
     }
}

一個小的補充是:

我的目標是知道服務是否正在運行,而如果它沒有運行,則不會實際運行它。

調用 bindService 或調用可以被服務捕獲的意圖不是一個好主意,因為如果服務未運行,它將啟動服務。

所以,正如奇跡2k所建議的,最好是在服務類中有一個靜態字段來知道服務是否已經啟動。

為了使它更簡潔,我建議將服務轉換為具有非常非常懶惰的獲取的單例:也就是說,沒有通過靜態方法對單例實例進行任何實例化。 您的服務/單例的靜態 getInstance 方法僅返回單例的實例(如果已創建)。 但它實際上並沒有啟動或實例化單身人士本身。 該服務僅通過正常的服務啟動方法啟動。

然后修改單例設計模式以將令人困惑的 getInstance 方法重命名為類似於isInstanceCreated() : boolean方法的內容會更清晰。

代碼將如下所示:

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

此解決方案很優雅,但僅當您有權訪問服務類並且僅適用於服務的應用程序/包旁邊的類時才相關。 如果您的類在服務應用程序/包之外,那么您可以使用 Pieter-Jan Van Robays 強調的限制查詢 ActivityManager。

你可以使用這個(我還沒有嘗試過,但我希望它有效):

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 service)

我認為這不像檢查,因為它正在啟動服務,因此您可以添加stopService(someIntent); 在代碼下。

/**
 * 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;
}

Android文檔的摘錄:

sendBroadcast(Intent)類似,但如果Intent有任何接收器,此函數將阻塞並在返回之前立即分派它們。

將此黑客視為“ping” Service 由於我們可以同步廣播,所以我們可以在 UI 線程上同步廣播並獲取結果。

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;   
        }
    }

在許多應用中的贏家,當然,對被設置為服務的靜態布爾場trueService.onCreate()並以falseService.onDestroy()因為它是一個簡單多了。

檢查服務是否正在運行的正確方法是簡單地詢問它。 在您的服務中實現一個 BroadcastReceiver 來響應來自您的活動的 ping。 服務啟動時注冊 BroadcastReceiver,服務銷毀時取消注冊。 從您的活動(或任何組件)向服務發送本地廣播意圖,如果它有響應,您就知道它正在運行。 注意下面代碼中 ACTION_PING 和 ACTION_PONG 之間的細微差別。

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;
            }
        }
    };
}

我稍微修改了上面介紹的解決方案之一,但傳遞了類而不是通用字符串名稱,以確保比較來自同一方法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;
    }
}

進而

Boolean isServiceRunning = ServiceTools.isServiceRunning(
                    MainActivity.this.getApplicationContext(),
                    BackgroundIntentService.class);

另一種使用 kotlin 的方法。 靈感來自其他用戶的答案

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 }
}

作為 kotlin 擴展

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 }
}

用法

context.isMyServiceRunning(MyService::class.java)

我只想在@Snicolas 的答案中添加注釋。 以下步驟可用於在調用/不調用onDestroy()情況下檢查停止服務。

  1. onDestroy()調用:轉到設置 -> 應用程序 -> 運行服務 -> 選擇並停止您的服務。

  2. onDestroy() not Called:轉至設置 -> 應用程序 -> 管理應用程序 -> 選擇並“強制停止”運行服務的應用程序。 但是,由於您的應用程序在此處停止,因此服務實例肯定也會停止。

最后,我想提一下,那里提到的在單例類中使用靜態變量的方法對我有用。

同樣,如果人們使用掛起的意圖(例如使用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是您在類中私下定義的常量,用於標識與您的服務關聯的待處理意圖。

onDestroy並不總是在服務中調用,所以這是無用的!

例如:只需在 Eclipse 中進行一次更改即可再次運行該應用程序。 使用 SIG: 9 強制退出應用程序。

首先,您不應該使用ActivityManager訪問服務。 這里討論)

服務可以獨立運行,也可以綁定到一個 Activity 或兩者兼而有之。 如果您的 Service 正在運行,則檢查 Activity 的方法是創建一個接口(擴展 Binder),您可以在其中聲明ActivityService理解的方法。 您可以通過創建自己的接口來實現這一點,例如在其中聲明“ isServiceRunning() ”。 然后,您可以將您的活動綁定到您的服務,運行方法 isServiceRunning(),服務將檢查自己是否正在運行,並向您的活動返回一個布爾值。

您還可以使用此方法停止您的服務或以其他方式與其交互。

Xamarin C# 版本:

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;
}

下面是一個優雅的 hack,涵蓋了所有Ifs 這僅適用於本地服務。

    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(...);
    }

對於此處給出的用例,我們可以簡單地使用stopService()方法的返回值。 如果存在指定的服務並被殺死,則返回true 否則它返回false 因此,如果結果為false您可以重新啟動服務,否則可以確保當前服務已停止。 :) 如果你看看這個會更好。

geekQ 但在 Kotlin 類中的響應。 謝謝極客Q

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)

在您的服務子類中使用靜態布爾值來獲取服務的狀態,如下所示。

我的服務.kt

class MyService : Service() {
    override fun onCreate() {
        super.onCreate()
        isServiceStarted = true
    }
    override fun onDestroy() {
        super.onDestroy()
        isServiceStarted = false
    }
    companion object {
        var isServiceStarted = false
    }
}

主活動.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)
        }
    }
}

對於 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
}

在 TheServiceClass 中定義:

 public static Boolean serviceRunning = false;

然后在 onStartCommand(...)

 public int onStartCommand(Intent intent, int flags, int startId) {

    serviceRunning = true;
    ...
}

 @Override
public void onDestroy()
{
    serviceRunning = false;

} 

然后,從任何類調用if(TheServiceClass.serviceRunning == true)

在 kotlin 中,您可以在伴隨對象中添加布爾變量,並從您想要的任何類中檢查其值:

companion object{
     var isRuning = false

}

創建和銷毀服務時更改它的值

 override fun onCreate() {
        super.onCreate()
        isRuning = true
    }

override fun onDestroy() {
    super.onDestroy()
    isRuning = false
    }

可以有多個服務具有相同的類名。

我剛剛創建了兩個應用程序。 第一個應用程序的包名稱是com.example.mock 我在應用程序中創建了一個名為lorem的子包和一個名為Mock2Service的服務。 所以它的全名是com.example.mock.lorem.Mock2Service

然后我創建了第二個應用程序和一個名為Mock2Service的服務。 第二個應用程序的包名稱是com.example.mock.lorem 服務的完全限定名稱也是com.example.mock.lorem.Mock2Service

這是我的 logcat 輸出。

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

更好的方法是比較ComponentName實例,因為equals()ComponentName比較兩個包名和類名。 並且不能在設備上安裝兩個具有相同包名的應用程序。

ComponentName的 equals() 方法。

@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;
}

組件名稱

簡單使用綁定,不要創建自動 - 請參閱 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);

為什么不使用? 獲取運行服務()

List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.

注意:此方法僅用於調試或實現服務管理類型的用戶界面。


附: android 文檔具有誤導性 我在 google tracker 上打開了一個問題以消除任何疑問:

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 的方法中調用:

 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,所以在我剖析休息電話之前,我暫停了我的回答。

但檢查服務是否正在運行的最佳方法是創建綁定(如果沒有創建綁定,則服務不存在) - 並通過綁定查詢服務的狀態(使用存儲在其狀態上的內部標志)。

更新 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;
}

簡而言之 :)

“為已綁定的服務提供綁定器。此方法是同步的,如果目標服務不存在,則不會啟動它。”

public IBinder peekService(意圖服務,字符串解析類型,字符串調用包)拋出遠程異常;

*

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;
}

*

請使用此代碼。

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;
    }

檢測服務是否正在運行的唯一有效/最快/干凈的方法是創建 PING/PONG 功能。

在服務內部實現 Messenger 或 AIDL 方法: isAlive() - 返回服務的狀態。

實現廣播,因為它們可以錯過。

這更適用於意圖服務調試,因為它們產生了一個線程,但也可能適用於常規服務。 感謝 Binging,我找到了這個線程

就我而言,我使用調試器並找到了線程視圖。 它有點像 MS Word 中的項目符號圖標。 無論如何,您不必處於調試器模式即可使用它。 單擊該過程,然后單擊該按鈕。 任何 Intent 服務都會在它們運行時出現,至少在模擬器上是這樣。

如果該服務屬於另一個進程或APK,則使用基於ActivityManager 的解決方案。

如果您可以訪問其源代碼,只需使用基於靜態字段的解決方案。 但是我建議使用一個布爾值而不是一個 Date 對象。 在服務運行時,只需將其值更新為“現在”,並在完成后將其設置為 null。 從活動中,您可以檢查它是否為空或日期是否太舊,這意味着它沒有運行。

您還可以從您的服務發送廣播通知,指示正在運行更多信息,例如進度。

如果您有一個多模塊應用程序,並且您想從一個不依賴於包含該服務的模塊的模塊中知道該服務是否正在運行,您可以使用此功能:

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")

如果服務類名稱更改並且調用函數沒有相應更改,則此函數可能無法正常工作。

從 Android 8(或 Oreo)開始,API getRunningServices 已棄用 當然,您可以使用@SuppressWarnings("deprecation")來消除警告。

如果您的服務不需要有多個實例,以下是不使用 getRunninngServices 的方法:使用單例模式。

public class MyMusicService extends Service {

    private static MyMusicService instance = null;
    
    public static boolean isMyMusicServiceRunning() {
        return instance != null;
    }

然后,您可以從您的活動或其他地方調用MyMusicService.isMyMusicServiceRunning

這是我想出的很好的解決方案,但它僅適用於在單獨進程中運行的服務。 這可以通過在清單中添加android:process屬性來實現,例如

<service
        android:name=".ExampleService"
        android:process="com.example.service"
        ...

現在您的服務將以給定名稱在單獨的進程中運行。 從您的應用程序中,您可以致電

val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
activityManager.runningAppProcesses.any { it.processName == "com.example.service" }

如果服務正在運行,它將返回true ,否則返回false

重要提示:請注意,它會顯示您的服務何時啟動,但是當您禁用它時(意思是,在系統與它解除綁定后),該進程仍然存在。 所以你可以簡單地強制刪除它:

override fun onUnbind(intent: Intent?): Boolean {
    stopSelf()
    return super.onUnbind(intent)
}

override fun onDestroy() {
    super.onDestroy()
    killProcess(Process.myPid())
}

然后它完美地工作。

我基於ActivityManager::getRunningServices的答案的 kotlin 轉換。 將此功能放入活動中-

private fun isMyServiceRunning(serviceClass: Class<out Service>) =
    (getSystemService(ACTIVITY_SERVICE) as ActivityManager)
        .getRunningServices(Int.MAX_VALUE)
        ?.map { it.service.className }
        ?.contains(serviceClass.name) ?: false

放輕松,伙計們... :)

我認為最合適的解決方案是在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);
}

沒有特殊權限,沒有循環...簡單的方法,干凈的解決方案:)

如果您需要其他信息,請參閱鏈接

希望這可以幫助。

您可以使用 Android 開發人員選項中的此選項來查看您的服務是否仍在后台運行。

1. Open Settings in your Android device.
2. Find Developer Options.
3. Find Running Services option.
4. Find your app icon.
5. You will then see all the service that belongs to your app running in the background.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM