서비스가 Android에서 실행 중인지 확인하는 방법 백그라운드 서비스가 실행 중인지 어떻게

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

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

onDestroy 또는 onSometing 이벤트 또는 바인더 또는 정적 변수를 사용하는 모든 접근 방식은 개발자가 Android를 사용하여 프로세스를 종료하기로 결정하거나 언급 된 콜백 중 어떤 것이 호출되는지 여부를 알 수 없기 때문에 안정적으로 작동하지 않습니다. 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;
     }
}


답변

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

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

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를 쿼리 할 수 ​​있습니다.


답변

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

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);코드 아래에 추가 할 수 있습니다 .


답변

/**
 * 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 만이이 기능을 차단 텐트에 대한 수신기하고 즉시 반환하기 전에 그들을 파견합니다.

이 핵을 “핑”이라고 생각하십시오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()가 많은 간단하기 때문이다.