서비스가 Android에서 실행 중인지 확인하는 방법


936

백그라운드 서비스가 실행 중인지 어떻게 확인합니까?

서비스 상태를 전환하는 Android 활동이 필요합니다. 서비스가 켜져 있으면 켜고 끌 수 있습니다.



17
정답은 아래에 표시되어 있지 않습니다. stackoverflow.com/a/5921190/2369122
toidiu

1
@toidiu 만약 그것이 아직 nerfed되지 않았다면 getRunningTasks()아마 그럴 것이다.
Kevin Krumwiede

getSystemService () 함수를 사용하면 실행중인 모든 서비스를 검색 할 수 있습니다. 그것을 통해 루프하고 목록에 서비스가 존재하는지 확인하십시오. 작은 샘플 wiki.workassis.com/android-check-the-service-is-running
Bikesh M

답변:


292

얼마 전 같은 문제가있었습니다. 내 서비스가 로컬이기 때문에 hackbod에 설명 된 것처럼 서비스 클래스에서 정적 필드를 사용하여 상태를 전환했습니다 .

편집 (레코드 용) :

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

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

우리는 의도적으로 코드에서 경쟁 조건으로 끝나는 것을 원할 때 거의 확실하게 서비스가 실행되고 있는지 확인하는 API가 없습니다.


27
@Pacerier, 참조하는 솔루션은 서비스를 시작해야하며 최상의 유연한 솔루션을 사용하면 서비스를 시작하지 않고 서비스가 실행 중인지 확인할 수 있어야합니다.
Tom

17
서비스가 시스템에 의해 중지되면 어떻게 감지하고 변수를 토글합니까?
jmng

23
앱이 종료되면 시작된 서비스도 종료되지만 서비스 onDestroy()는 호출되지 않습니다. 따라서 이러한 시나리오에서는 정적 변수를 업데이트 할 수 없어 동작이 일관되지 않습니다.
faizal

5
@faizal 정적 변수도 다시 초기화되어 서비스가 더 이상 실행되지 않음을 나타내는 기본값으로 다시 설정하지 않습니까?
PabloC

12
@ faizal, 로컬 서비스는 별도의 프로세스가 아니므로 서비스가 종료되면 앱도 종료됩니다.
Sever

1674

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

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를 통해 Android 운영 체제에서 제공하는 서비스 실행에 대한 정보를 기반으로하기 때문에 안정적으로 작동합니다 .

onDestroy 또는 onSometing 이벤트 또는 바인더 또는 정적 변수를 사용하는 모든 접근 방식은 개발자가 Android를 사용하여 프로세스를 종료하기로 결정하거나 언급 된 콜백 중 어떤 것이 호출되는지 여부를 알 수 없기 때문에 안정적으로 작동하지 않습니다. Android 설명서 의 수명주기 이벤트 표 에서 "킬 수 있음"열을 확인하십시오 .


85
이 솔루션에 감사드립니다. 내가 추가 할 대신 "com.example.MyService는"MyService.class.getName ()를 사용하는 것이 더 우아
peter.bartos

10
개인적으로 정적 필드를 사용했습니다. getRunningServices ()를 사용하는 것이 더 강력한 솔루션이지만이 두 솔루션에는 견고성과 효율성 / 단순성 사이의 균형이 있다고 생각합니다. 서비스가 실행 중인지 자주 확인해야하는 경우 30 개 이상의 실행중인 서비스를 통한 루핑은 그리 이상적이지 않습니다. 시스템에 의해 서비스가 파괴되는 드문 경우는 try / catch 블록 또는 START_STICKY를 사용하여 처리 할 수 ​​있습니다.
robguinness

80
문서에 다음과 같이 쓰여 있기 때문에 정답이 아닙니다. "참고 :이 방법은 서비스 관리 유형 사용자 인터페이스를 디버깅하거나 구현하기위한 것입니다." 제어 흐름을위한 것이 아닙니다!
seb

40
사람들은 서버가 실행 중인지 확인하기 위해 모든 것을 거쳐야하는 것이 우아하다고 생각합니까?
Rui Marques

80
시작 안드로이드 O를 , getRunningServices사용되지 않습니다. 이 답변에는 최신 버전에 대한 업데이트가 필요합니다.
poring91

75

알았다!

당신은 반드시 전화 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;
     }
}

시스템 서비스 만 표시됩니다. 그래서 내 지역 서비스가 목록에서 제외되고 거짓이 될 것입니다. (
Ewoks

이것은 외부 서비스와 함께 작동합니다. 로컬 서비스는 실행중인 경우 분명합니다.
케빈 파커

11
미안하지만 나는 그것이 어리석은 대답이라고 말할 필요가있다. 왜 슈퍼 명백한가?!
Ewoks

10
무슨 뜻인지 모르겠지만 ... 누가 충돌에 대해 이야기하고 있었습니까?! 나는 그것을 추락하는 데 흥미가 없다. 서비스는 시작, 중지, 의도 된 서비스 일 수 있으며 완료되면 자체적으로 중지 될 수 있습니다 ... 질문은 예를 들어 3 분 후에도 여전히 실행 중인지 여부를 확인하는 방법입니다.
Ewoks

1
바운드 서비스도 시작해야한다는 인상을주는 것은 잘못된 것입니다. 아니. 바인드 자동 작성은 정확하게 말합니다. 서비스가 아직 실행되고 있지 않은 경우 서비스를 작성 ( "시작")합니다.
Sreedevi J

57

작은 보완책은 다음과 같습니다.

내 목표는 서비스가 실행 중이 아닌 경우 실제로 실행하지 않고 서비스가 실행되고 있음을 아는 것입니다.

bindService를 호출하거나 서비스에 의해 잡힐 수있는 의도를 호출하는 것은 서비스가 실행 중이 아닌 경우 서비스를 시작하기 때문에 좋은 생각이 아닙니다.

따라서 miracle2k가 제안했듯이 서비스 클래스에 서비스가 시작되었는지 여부를 알기 위해 정적 필드를 갖는 것이 가장 좋습니다.

더 깨끗하게하기 위해 매우 게으른 인출으로 단일 톤으로 서비스를 변환하는 것이 좋습니다. 즉, 모든 단일 톤 에서 인스턴스화가 없습니다. 정적 메서드를 통해 인스턴스 . 서비스 / 싱글 톤의 정적 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를 쿼리 할 수 ​​있습니다.


32
이것은 결함이 있습니다. onDestroy가 호출되는 것은 아닙니다.
Pacerier

8
시스템의 메모리가 부족하면 onDestroy를 호출하지 않고도 서비스가 자동으로 종료되므로 결함이 있다고 말합니다.
Pacerier

17
@Pacerier, 그러나 시스템이 프로세스를 종료하더라도 인스턴스 플래그는 여전히 재설정됩니다. 수신자가 다음에로드 될 때 (시스템을 종료시키는 시스템 게시) 정적 플래그 '인스턴스'가 null로 다시 생성 될 것이라고 추측합니다.
Tom

2
isMyServiceRunning의 모든 서비스를 반복하는 것보다 적어도 더 좋습니다. 모든 장치 회전에서 수행되는 경우 실제로 지연됩니다. :)
Gunnar Forsgren-Mobimation

1
인스턴스 변수는 final로 선언해서는 안되며, 그렇지 않으면 onCreate () 또는 onDestroy () 메소드로 설정하거나 널 (null)로 설정할 수 없습니다.
k2col

27

이것을 사용할 수 있습니다 (아직 시도하지는 않았지만 이것이 효과가 있기를 바랍니다).

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이 반환됩니다.

public abstract ComponentName startService (의도 서비스)를 참조하십시오 .

이것은 서비스를 시작하기 때문에 내가 생각하는 확인과는 다르므로 stopService(someIntent);코드 아래에 추가 할 수 있습니다 .


11
문서가 정확히 말한 것은 아닙니다. "서비스가 시작 중이거나 이미 실행중인 경우 시작된 실제 서비스의 ComponentName이 반환되고 서비스가 존재하지 않으면 null이 반환됩니다."
Gabriel

좋은 생각 ...하지만 현재 상황에 맞지 않습니다.
Code_Life

5
IDE 트리거시 if(startService(someIntent) != null)이를 확인 IsserviceRunning하지만 새로운 서비스를 수행 하기 때문에 적절한 방법이 아닙니다 .
친탄 케티 야

언급 한 바와 같이,이 제어 후에 서비스를 중지하면이 문제에 유용합니다. 그러나 왜 서비스를 시작하고 중지해야합니까?
Taner

6
이것은 서비스를 시작하지 않습니까? 서비스를 시작하는 대신 상태를 확인하고 싶을
Raptor

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

21

Android 문서 에서 추출한 내용 :

마찬가지로 (의도) sendBroadcast 만이이 기능을 차단 텐트에 대한 수신기하고 즉시 반환하기 전에 그들을 파견합니다.

이 핵을 "핑"이라고 생각하십시오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;   
        }
    }

많은 응용 프로그램의 우승자는 물론,로 설정되어있는 서비스에 정적 부울 필드 true에서 Service.onCreate()와에 false에서 Service.onDestroy()가 많은 간단하기 때문이다.


이것은 전역 변수 메소드가 실제로 더 이상 서비스를 제공하지 않을 때 서비스가 실행되고 있음을 나타내므로 Android가 서비스를 종료하면 실패하는 허용되는 솔루션보다 훨씬 나은 솔루션입니다. 이 동기식 탁구 브로드 캐스트 트릭은 실제로 서비스가 살아 있는지 확인하는 유일한 신뢰할 수있는 방법입니다. 서비스 만 있으면 서비스를 요청할 수 있습니다. 응답하면 서비스가 활성 상태이며 실행 중이 아니면 서비스가 시작되지 않았거나 프로그램 방식으로 또는 시스템에 의해 종료되어 메모리를 복구하는 것입니다.
PhoenixRevealed

13

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

엄격한 측면에서 더 많은 것을 위해 당신은 class param을 다음과 같이 바꿀 수 있습니다Class<? extends Service>
silentsudo

11

서비스가 실행 중인지 확인하는 올바른 방법은 간단히 요청하는 것입니다. 활동의 핑에 응답하는 서비스에 BroadcastReceiver를 구현하십시오. 서비스가 시작될 때 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;
            }
        }
    };
}

1
나는 실제로이 접근법을 좋아한다. 약간 현명한 코드이지만 항상 작동합니다. 방송 의도가 곧 더 이상 사용되지 않을 것으로 보입니다. :)
ShellDude

8

@ Snicolas의 답변에 메모를 추가하고 싶습니다. 다음 단계를 사용하여 호출 유무에 관계없이 서비스 중지를 확인할 수 있습니다 onDestroy().

  1. onDestroy() 호출 됨 : 설정-> 응용 프로그램-> 서비스 실행-> 서비스 선택 및 중지로 이동하십시오.

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

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


7

onDestroy 서비스에서 항상 호출되지는 않으므로 쓸모가 없습니다!

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


6

먼저 ActivityManager를 사용하여 서비스에 접근하지 마십시오. ( 여기서 논의 )

서비스는 자체적으로 실행되거나 활동에 바인딩되거나 둘 다에 바인딩 될 수 있습니다. 서비스가 실행 중인지 활동을 체크인하는 방법은 활동과 서비스 모두 이해하는 메소드를 선언하는 인터페이스 (바인더 확장)를 작성하는 것입니다. "isServiceRunning ()"과 같이 선언 한 곳에 고유 한 인터페이스를 만들어서이를 수행 할 수 있습니다. 그런 다음 활동을 서비스에 바인드하고 isServiceRunning () 메소드를 실행하면 서비스가 실행 중인지 여부를 확인하고 활동에 부울을 리턴합니다.

이 방법을 사용하여 서비스를 중지하거나 다른 방식으로 서비스와 상호 작용할 수도 있습니다.

자습서 를 사용하여 응용 프로그램에서이 시나리오를 구현하는 방법을 배웠습니다.


3
그 토론은 '12 / 26 / 07 '에서 열렸습니다. 올해 7 월 (즉, 미래)이거나 Android가 공개되기 전입니다. 어느 쪽이든 내가 그것을 믿지 못하게합니다.
Tom

이 토론은 2007 년 12 월 26 일부터 시작 되었습니다. 2007 년 12 월 14 일에 릴리스 된 시험판 ( developer.android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a )에 대해 논의 중입니다.
ingh.am

6

다시 말하지만 사람들이 보류중인 의도를 사용하면 더 깨끗하게 찾을 수있는 또 다른 대안 (예 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서비스와 관련된 보류중인 의도를 식별하기 위해 클래스에서 개인적으로 정의하는 상수는 어디에 있습니까 ?


1
이전 답변을 결합하거나 업데이트하십시오. 게시물 당 두 개 이상의 답변을 게시하지 마십시오.
ChuongPham

이 답변을 확장 할 수 있습니까? 즉, CODE의 가치를 서비스와 어떻게 연결합니까?
Dave Nottage

컨텍스트를 얻을 수있는 곳은?
바질

6

아래는 모든 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(...);
    }

이 문제의 유일한 문제점은 서비스가 고정 서비스이고 자체적으로 재시작되는 경우입니다. mInstance가 null이므로 서비스를 다시 시작한 후 isServiceCreated ()를 호출하면 false가 반환됩니다.
Mira_Cole

1
서비스가 다시 시작될 때 onCreate가 호출되지 않습니까?
TheRealChx101 2018 년

6

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

에 대한 '컨텍스트'가 필요합니다 GetSystemService.
테스트

5

여기에 주어진 유스 케이스의 경우 단순히 stopService()메소드의 반환 값 을 사용할 수 있습니다 . true지정된 서비스가 존재하고 종료 되면 반환 합니다. 그렇지 않으면를 반환합니다 false. 결과가 false현재 서비스가 중지되었다고 확신 하면 서비스를 다시 시작할 수 있습니다 . :) 이것을 보면 더 좋을 것 입니다.


5

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)

4

kotlin에서는 컴패니언 객체에 부울 변수를 추가하고 원하는 클래스에서 값을 확인할 수 있습니다.

companion object{
     var isRuning = false

}

서비스 생성 및 파괴시 값 변경

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

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

3

서비스 하위 클래스에서 정적 부울을 사용하여 아래에 설명 된대로 서비스 상태를 가져옵니다.

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

3

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
}

이것은 작업 코드를 변경하지 않고도 테스트를 작성할 수 있기 때문에 테스트 작성에 큰 도움이됩니다.
Robert Liberatore

2

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)

6
ActivityManager.getRunningServices
Daniel

1

클래스 이름이 같은 여러 서비스가있을 수 있습니다.

방금 두 개의 앱을 만들었습니다. 첫 번째 앱의 패키지 이름은입니다 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


1

이 코드를 사용하십시오.

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

0

스레드를 생성하기 때문에 인 텐트 서비스 디버깅에 더 많이 적용되지만 일반 서비스에서도 작동 할 수 있습니다. Binging 덕분 에이 스레드를 발견했습니다.

필자의 경우 디버거를 가지고 놀면서 스레드보기를 찾았습니다. 그것은 MS Word의 글 머리 기호 아이콘처럼 보입니다. 어쨌든, 그것을 사용하기 위해 디버거 모드에있을 필요는 없습니다. 프로세스를 클릭하고 해당 버튼을 클릭하십시오. 실행중인 서비스는 적어도 에뮬레이터에서 표시됩니다.


0

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

소스에 액세스 할 수 있으면 정적 필드를 기반으로하는 솔루션을 사용하십시오. 그러나 대신 부울을 사용하면 Date 객체를 사용하는 것이 좋습니다. 서비스가 실행되는 동안 값을 'now'로 업데이트하고 완료되면 null로 설정하십시오. 활동에서 널 또는 날짜가 너무 오래된 지 점검하여 실행 중이 아님을 확인할 수 있습니다.

또한 서비스에서 진행률과 같은 추가 정보를 따라 실행 중임을 나타내는 브로드 캐스트 알림을 보낼 수도 있습니다.


0

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)모든 수업에서 전화 하십시오.


4
Android에 의해 서비스가 종료되면 작동하지 않습니다.
Heisenberg

@ Heisenberg 나는 방금 저 자신을 경험했습니다. 왜 그런지 아십니까?
Tim

@Heisenberg는 내 앱이 OS에 의해 종료되면 서비스가 다시 시작되고 정적 부울을 true로 설정하지만 잘못된 정보를보고하면 거짓으로보고됩니다.
Tim

전화하면 작동하지 않습니다 stopService. 적어도 인 텐트 서비스의 경우. onDestroy()즉시 호출되지만 onHandleIntent()여전히 실행됩니다
serggl

1
@Heisenberg 메모리 부족으로 인해 서비스를 종료하지 않아도 프로세스가 종료되는 것을 의미합니까?
안드로이드 개발자

0

간단한 사용 바인드로 자동 생성 안 함-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

우리가 볼 수 있듯이 바인드 서비스는 실제로 서비스 캐시 바인더를 통해 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;
}

한마디로 :)

"이미 바인딩 된 서비스에 바인더를 제공합니다.이 방법은 동기식이며 대상 서비스가없는 경우 대상 서비스를 시작하지 않습니다."

공용 IBinder peekService (의도 서비스, 문자열 resolveType, 문자열 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;
}

*


서비스가 실행되고 있지 않으면 bindResult (bindService 메소드의 리턴 값)가 false가되지 않습니다.
Shangeeth Sivan

0

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

-2

서비스가 백그라운드에서 여전히 실행 중인지 확인하기 위해 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.

-5

쉬운 사람을 가져 가라 ... :)

가장 적합한 솔루션은 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);
}

특별한 권한, 루프가 없습니다 ... 쉬운 방법, 깨끗한 솔루션 :)

추가 정보가 필요하면 링크 를 참조하십시오

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


19
그들이 서비스를 죽일 때 아무도 당신을 위해 가치를 업데이트하지 않습니다
Gunnar Forsgren-Mobimation

서비스를 종료하면 onDestroy ()가 트리거되고 상태를 업데이트 할 수 있습니다.
Jongz Puangput

5
@JongzPuangput onDestroy은 서비스가 종료 될 때 항상 호출되는 것은 아닙니다. 예를 들어, 메모리 부족 상황에서 서비스 onDestroy가 호출 되지 않고 종료 되는 것을 보았습니다 .
Sam

@Sam 그러면 무엇이 불려 질까요?
Ruchir Baronia

2
@RuchirBaronia 내가 기억하는 한, 물건을 죽일 때 알림을받지 않습니다. 나는 안드로이드가 필요에 따라 앱을 죽 이도록 설계되었다고 생각하며, 앱은 알림없이 언제라도 죽을 것으로 예상되어야합니다.
Sam
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.