Android에서 서비스가 실행되고 있는지 확인하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/600207

  •  03-07-2019
  •  | 
  •  

문제

백그라운드 서비스가 실행 중인지 어떻게 확인하나요?

나는 서비스 상태를 전환하는 Android 활동을 원합니다. 서비스가 꺼져 있으면 켤 수 있고 켜져 있으면 끌 수 있습니다.

도움이 되었습니까?

해결책

얼마 전까지도 같은 문제가있었습니다. 내 서비스가 현지 였기 때문에 HackBod가 설명한대로 서비스 클래스의 정적 필드를 사용하여 상태를 사용했습니다. 여기

편집 (레코드 용) :

HackBod가 제안한 솔루션은 다음과 같습니다.

클라이언트와 서버 코드가 동일한 .apk의 일부이고 구체적인 의도 (정확한 서비스 클래스를 지정하는)로 서비스에 바인딩하는 경우 서비스가 실행 중일 때 전역 변수를 설정할 수 있습니다. 고객이 확인할 수 있습니다.

우리는 고의적으로 서비스가 실행되는지 확인하기위한 API가 없습니다. 코드에서 레이스 조건으로 끝나는 것과 같은 일을하고 싶을 때 거의 실패하지 않기 때문입니다.

다른 팁

나는 활동 내부에서 다음을 사용합니다.

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)

이것은 안드로이드 운영 체제가 제공하는 실행 서비스에 대한 정보를 기반으로하기 때문에 안정적으로 작동합니다. ActivityManager#getRunningservices.

ondestroy 또는 onsometing 이벤트 또는 바인더 또는 정적 변수를 사용하는 모든 접근 방식은 개발자로서 Android가 프로세스를 죽이기로 결정했을 때 또는 언급 된 콜백이 호출되는지 여부를 알지 못하기 때문에 안정적으로 작동하지 않습니다. "킬 가능한"열에 주목하십시오 수명주기 이벤트 테이블 안드로이드 문서에서.

알았어요!

해야 하다 전화 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;
     }
}

작은 보완 사항은 다음과 같습니다.

내 목표는 서비스가 실행되고 있지 않은 경우 실제로 실행하지 않고도 서비스가 실행 중인지 확인하는 것입니다.

서비스가 실행되고 있지 않은 경우 서비스를 시작하므로 서비스에서 포착할 수 있는 바인딩 서비스를 호출하거나 인텐트를 호출하는 것은 좋은 생각이 아닙니다.

따라서 기적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();
}

STARKERVICE 메소드는 이미 실행중인 서비스가있는 경우 ComponentName 객체를 반환합니다. 그렇지 않으면 NULL이 반환됩니다.

보다 공개 초록 구성 요소 이름 StartService (의도 서비스).

이것은 서비스를 시작하기 때문에 내가 생각하는 것과 같지 않으므로 추가 할 수 있습니다. stopService(someIntent); 코드에 따라.

    public boolean checkServiceRunning(){
         ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) 
                {
                    if ("com.example.yourpackagename.YourServiceName"
                            .equals(service.service.getClassName())) 
                    {
                        return true;
                    }
                }
             return false;
    }

위에 제시된 솔루션 중 하나를 약간 수정했지만 동일한 방법에서 나오는 문자열을 비교하기 위해 일반 문자열 이름 대신 클래스를 통과했습니다. 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);

에서 추출 기계적 인조 인간 문서:

좋다 sendBroadcast(의도), 그러나 의도에 대한 수신기가 있으면이 기능은 돌아 오기 전에 즉시 파견됩니다.

이 해킹을 "핑"하는 것으로 생각하십시오. Service 동기적으로 브로드캐스트할 수 있으므로 UI ​​스레드에서 동기적으로 브로드캐스트하고 결과를 얻을 수 있습니다.

Service

@Override
public void onCreate() {
   LocalBroadcastManager
     .getInstance(this)
     .registerReceiver(new ServiceEchoReceiver(), new IntentFilter("ping"));
}

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

@Snicolas의 답변에 메모를 추가하고 싶습니다. 다음 단계는 전화를받지 않은 경우 중지 서비스를 확인하는 데 사용할 수 있습니다. onDestroy().

  1. onDestroy() 호출 : 설정 -> 응용 프로그램 -> 서비스 -> 서비스를 선택하고 중지하십시오.

  2. onDestroy() 호출되지 않음 : 설정 -> 응용 프로그램 -> 응용 프로그램 관리 -> 서비스가 실행중인 애플리케이션을 선택하고 "강제 중지"하십시오. 그러나 응용 프로그램이 여기에서 중지되므로 서비스 인스턴스도 중지됩니다.

마지막으로, 싱글 톤 클래스에서 정적 변수를 사용하여 언급 된 접근법이 저에게 효과가 있다고 언급하고 싶습니다.

onDestroy 서비스에서 항상 호출되는 것은 아니므로 이것은 쓸모가 없습니다!

예를 들어, Eclipse에서 한 번의 변경으로 앱을 다시 실행하십시오. SIG : 9를 사용하여 응용 프로그램이 강제로 종료됩니다.

서비스가 실행 중인지 확인하는 적절한 방법은 간단히 물어 보는 것입니다. 활동에서 핑에 응답하는 서비스에서 광대역을 구현하십시오. 서비스가 시작될 때 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;
            }
        }
    };
}

우선 당신은 ActivityManager를 사용하여 서비스에 도달하려고하지 않습니다. (논의 여기)

서비스는 자체적으로 실행되거나 활동 또는 둘 다에 구속 될 수 있습니다. 서비스가 실행 중이든 그렇지 않은 경우 활동을 체크인하는 방법은 인터페이스 (바인더를 확장하는)를 만드는 것입니다. 여기서 활동과 서비스가 모두 이해하는 방법을 선언합니다. 예를 들어 "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;
}

여기에 주어진 사용 사례를 위해 우리는 단순히 stopService() 방법의 반환 값. 돌아옵니다 true 지정된 서비스가 존재하고 사망 한 경우. 그렇지 않으면 돌아옵니다 false. 결과가 발생하면 서비스를 다시 시작할 수 있습니다. false 그렇지 않으면 현재 서비스가 중지되었음을 확신합니다. :) 당신이 보면 더 나을 것입니다 이것.

다시 말하지만, 사람들이 보류중인 의도를 사용하는 경우 (예 : 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 서비스와 관련된 보류 의도를 식별하기 위해 수업에서 개인적으로 정의하는 일정입니다.

아래는 모든 것을 다루는 우아한 해킹입니다 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(...);
    }

Geekq의 응답이지만 Kotlin 클래스에서. 감사합니다 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)

동일한 클래스 이름을 가진 여러 서비스가있을 수 있습니다.

방금 두 개의 앱을 만들었습니다. 첫 번째 앱의 패키지 이름은입니다 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 패키지 이름과 클래스 이름을 모두 비교합니다. 또한 장치에 동일한 패키지 이름이 설치된 두 개의 앱이 없습니다.

equals () 메소드 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

이는 스레드를 생성하기 때문에 의도 서비스 디버깅에 더 많이 적용되지만 일반 서비스에도 효과가있을 수 있습니다. 빙빙 덕분 에이 스레드를 찾았습니다

제 경우에는 디버거를 가지고 놀았고 스레드보기를 찾았습니다. MS Word의 총알 포인트 아이콘처럼 보입니다. 어쨌든, 당신은 그것을 사용하기 위해 디버거 모드에있을 필요는 없습니다. 프로세스를 클릭하고 해당 버튼을 클릭하십시오. 의도 서비스는 적어도 에뮬레이터에서 달리는 동안 나타납니다.

서비스가 다른 프로세스에 속하거나 APK가 ActivityManager를 기반으로 솔루션을 사용하는 경우.

소스에 액세스 할 수있는 경우 정적 필드를 기반으로 솔루션을 사용하십시오. 그러나 부울을 사용하여 날짜 개체를 사용하는 것이 좋습니다. 서비스가 실행되는 동안 값을 'Now'로 업데이트하고 완료되면 NULL로 설정하십시오. 활동에서 NULL 또는 날짜가 너무 오래되었는지 확인할 수있어 실행되지 않음을 의미합니다.

또한 진행과 같은 추가 정보를 따라 실행되고 있음을 나타내는 서비스에서 방송 알림을 보낼 수도 있습니다.

내부 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) 모든 수업에서.

간단한 사용 Bind with Not Create Auto - 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.

참고 :이 방법은 서비스 관리 유형 사용자 인터페이스를 디버깅하거나 구현하기위한 것입니다.


추신. 안드로이드 문서는 오해의 소지가 있습니다. Google 트래커에서 문제를 일으켜 의심의 여지를 제거했습니다.

https://issuetracker.google.com/issues/68908332

우리가 볼 수 있듯이 BIND Service는 실제로 서비스 캐시 바인더를 통해 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에서 파는 시간이 없으므로 휴식 전화를 해부 할 때까지 대답을 중단합니다.

그러나 서비스가 실행 중인지 확인하는 가장 좋은 방법 바인드를 생성하는 것입니다 (Bind가 생성되지 않은 경우 서비스가 존재하지 않는 경우) - BIND를 통해 상태에 대한 서비스를 쿼리합니다 (State State에 저장된 내부 플래그 사용).

업데이트 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;
}

간단히 말해 :)

"이미 바운드 서비스에 바인더를 제공하십시오.이 방법은 동기식이며 대상 서비스가 존재하지 않으면 시작하지 않습니다."

공개 iBinder PeekService (의도 서비스, 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;
}

*

서비스 하위 클래스에서 정적 부울을 사용하여 아래에 표시된대로 서비스 상태를 얻으십시오.

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

내 코 틀린 변환 ActivityManager::getRunningServices 기반 답변. 이 기능을 활동에 넣으십시오.

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

이 코드를 사용하십시오.

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

쉬운 남자들 ... :)

가장 적합한 솔루션은 키 값 쌍을 보유하고 있다고 생각합니다. SharedPreferences 서비스가 실행 중인지 여부에 대해

논리는 매우 똑 바르고; 서비스 클래스에서 원하는 위치에서; 서비스가 실행 중인지 아닌지에 대한 깃발 역할을하는 부울 가치를 넣으십시오. 그런 다음 응용 프로그램에서 원하는 곳 에서이 값을 읽으십시오.

내 앱에서 사용중인 샘플 코드는 다음과 같습니다.

내 서비스 클래스 (오디오 스트림 서비스)에서 서비스가 UP가있을 때 다음 코드를 실행합니다.

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

특별한 권한 없음, 고리 없음 ... 쉬운 방법, 깨끗한 솔루션 :)

추가 정보가 필요한 경우 참조하십시오 링크

도움이 되었기를 바랍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top