programing

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

showcode 2023. 6. 4. 10:46
반응형

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

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

저는 서비스 상태를 전환하는 안드로이드 활동을 원합니다. 서비스가 켜져 있으면 켜고 끌 수 있게 해줍니다.

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

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

Destroy 또는 OnSoming events, Binders 또는 정적 변수에서 사용하는 모든 접근 방식은 안정적으로 작동하지 않습니다. Android가 프로세스를 종료하기로 결정했을 때 또는 언급된 콜백이 호출되거나 호출되지 않을 때 개발자가 알 수 없기 때문입니다.Android 설명서의 라이프사이클 이벤트 표에 있는 "killable" 열을 참조하십시오.

저는 얼마 전에도 같은 문제를 겪었습니다.제 서비스가 로컬이었기 때문에, 저는 여기 hackbod에서 설명한 것처럼 단순히 서비스 클래스의 정적 필드를 사용하여 상태를 전환했습니다.

편집(레코드용):

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

클라이언트 및 서버 코드가 동일한 .apk의 일부이고 특정 Intent(정확한 서비스 클래스를 지정하는 Intent)를 사용하여 서비스에 바인딩된 경우, 서비스가 실행 중일 때 클라이언트가 확인할 수 있는 글로벌 변수를 설정하도록 할 수 있습니다.

서비스가 실행 중인지 여부를 확인할 수 있는 API가 의도적으로 없습니다. 이는 거의 틀림없이 코드에 레이스 상태가 발생하기 때문입니다.

알았다!

전화해야 합니다.startService()의 서비스가 되어 합격할 수 합니다.BIND_AUTO_CREATE충분하지 않을 것입니다.

Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);

그리고 이제 서비스도구 클래스:

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로 밑줄이 그어진 제한 사항을 쿼리할 수 있습니다.

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

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(IntentService)참조하십시오.

것이기 하는 것과는 은 이은확같않다습니지를 할 수 . 서비스를 시작하고 있기 때문에 추가할 수 있습니다.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 문서에서 발췌:

브로드캐스트 전송(Intent)과 마찬가지로, 그러나 Intent에 대한 수신자가 있으면 이 함수는 차단하고 즉시 전송한 후 반환합니다.

이 해킹을 "ping"이라고 생각하시면 됩니다. 동기식으로 방송할 수 있기 때문에 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()훨씬 더 간단하기 때문입니다.

코틀린을 이용한 또 다른 접근법.다른 사용자의 답변에 영감을 받았습니다.

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

애스코틀린 확장자

fun Context.isMyServiceRunning(serviceClass: Class<out Service>) = try {
    (getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
        .getRunningServices(Int.MAX_VALUE)
        .any { it.service.className == serviceClass.name }
} catch (e: Exception) {
    false
}

사용.

context.isMyServiceRunning(MyService::class.java)

서비스가 실행 중인지 확인하는 올바른 방법은 단순히 서비스에 문의하는 것입니다.활동에서 발생하는 ping에 응답하는 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;
            }
        }
    };
}

중을 확실히 이름 했습니다.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);

저는 @Snicolas의 답변에 메모를 추가하고 싶습니다.하여 전화를 걸지 않고 서비스 중지를 할 수 .onDestroy().

  1. onDestroy()파일: - 중 ->합니다.설정 -> 응용프로그램 -> 서비스 실행 중 -> 서비스를 선택하고 중지합니다.

  2. onDestroy()파일: -> - ->중인 중지.설정 -> 응용프로그램 -> 응용프로그램 관리 -> 서비스가 실행 중인 응용프로그램을 선택하고 "강제 중지"합니다.그러나 여기서 애플리케이션이 중지되므로 서비스 인스턴스도 당연히 중지됩니다.

마지막으로, 저는 싱글톤 수업에서 정적 변수를 사용하는 방법이 저에게 효과가 있다는 것을 언급하고 싶습니다.

인 의미를 들어, 다시, ▁the▁(▁if▁againents,대▁int다)를 사용하면 더 수 또 다른 대안이 .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);
}

에▁where디CODE서비스와 관련된 보류 중인 의도를 식별하기 위해 클래스에서 개별적으로 정의하는 상수입니다.

먼저 을(를) 사용하여 서비스에 액세스해서는 안 됩니다. (여기서는 설명합니다.)

서비스는 자체적으로 실행되거나 활동 또는 둘 다에 바인딩될 수 있습니다. 중인지 은 인터페이스가 두 가지 선언하는 입니다.Activity 리고그고.Service를 들어 "를들를 " 선하 " 신는언 " 만이자 " " 를 이러한 을 수행할 수 .isServiceRunning()그런 다음 활동을 서비스에 바인딩하고, method isServiceRunning()을 실행하면 서비스가 실행 중인지 여부를 자체적으로 확인하고, 활동에 부울을 반환합니다.

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

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

예를 들어, Eclipse에서 한 번만 변경하면 앱을 다시 실행할 수 있습니다.SIG: 9를 사용하여 애플리케이션을 강제로 종료합니다.

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

사마린 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그렇지 않으면 현재 서비스가 중지된 것으로 확인됩니다.:) 이걸 보시면 더 좋을 것 같습니다.

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)

서비스 하위 클래스에서 정적 부울을 사용하여 아래와 같이 서비스 상태를 확인합니다.

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

코틀린에서는 동반 객체에 부울 변수를 추가하고 원하는 클래스에서 값을 확인할 수 있습니다.

companion object{
     var isRuning = false

}

서비스가 생성 및 삭제될 때 값 변경

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

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

코틀린의 경우 아래 코드를 사용하시면 됩니다.

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
}

서비스 클래스 내부에서는 다음을 정의합니다.

 public static Boolean serviceRunning = false;

그러면 OnStart 명령어(...)

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

    serviceRunning = true;
    ...
}

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

} 

다음, 럼그, 콜콜로 전화하세요.if(TheServiceClass.serviceRunning == true)어느 반에서나

단순 사용 바인드 및 자동 생성 안 함참조 및 업데이트...

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.

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


ps. 안드로이드 문서는 오해의 소지가 있습니다. 저는 의심을 없애기 위해 구글 트래커에서 문제를 열었습니다.

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

이것은 활동에서 설정됩니다.스레드 경로:

 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를 파헤칠 시간이 없기 때문에 해부할 때까지 답변을 보류합니다.

그러나 서비스가 실행 중인지 확인하는 가장 좋은 방법은 바인딩을 만들고(바인딩이 생성되지 않은 경우 서비스가 존재하지 않음), 바인딩을 통해 서비스 상태를 쿼리하는 것입니다(바인딩 상태에 저장된 내부 플래그 사용).

2018년 6월 23일 업데이트

저는 그것들이 흥미롭다는 것을 알았습니다.

/**
 * 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(Intent 서비스, 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;
}

*

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

저는 방금 두 개의 앱을 만들었습니다. 번째 은 첫째앱패이름은지키입니다.com.example.mock다음과 같은 하위 패키지를 만들었습니다.lorem에 있는 것처럼 말입니다.Mock2Service그래서 그것의 완전한 자격을 갖춘 이름은.com.example.mock.lorem.Mock2Service.

그리고 두 번째 앱과 서비스를 만들었습니다.Mock2Service은 두번앱패이름은지입니다.com.example.mock.lorem의 정규화된 은 서스의정다같습다니음과이름은비입니다.com.example.mock.lorem.Mock2Service 무너.

여기 제 로그캣 출력물이 있습니다.

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패키지 이름과 클래스 이름을 비교합니다.또한 동일한 패키지 이름을 가진 두 개의 앱이 장치에 설치될 수 없습니다.

같은 ( )의 equalsComponentName.

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

구성요소 이름

이 코드를 사용하십시오.

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

다중 모듈 응용 프로그램이 있는 경우 서비스가 포함된 모듈에 종속되지 않는 모듈에서 서비스가 실행 중인지 여부를 확인하려면 다음 기능을 사용할 수 있습니다.

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

서비스 클래스 이름이 변경되고 그에 따라 호출 기능이 변경되지 않으면 이 기능이 제대로 작동하지 않을 수 있습니다.

제가 생각해 낸 좋은 해결책은 다음과 같습니다. 하지만 이 방법은 별도의 프로세스에서 실행되는 서비스에만 적용됩니다.은 이다음추달수있다니습성할여가하는을▁an▁adding다있니▁this를 추가함으로써 달성될 수 .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" }

은 느어것돌것인가올아이▁return가것인을 반환할 것입니다.true 중이고 서스가중경우인실인 false그렇지않으면.

중요: 서비스가 시작된 시점이 표시되지만 서비스를 비활성화해도(즉, 시스템이 서비스에서 바인딩 해제된 후) 프로세스가 활성화될 수 있습니다.따라서 강제로 제거할 수 있습니다.

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

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

그러면 완벽하게 작동합니다.

스레드를 생성하기 때문에 Intent Service 디버깅에 더 많이 적용되지만 일반 서비스에서도 작동할 수 있습니다.나는 빙잉 덕분에 이 실을 찾았습니다.

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

서비스가 다른 프로세스 또는 APK에 속해 있는 경우 Activity Manager를 기반으로 솔루션을 사용합니다.

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

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

한 의코틀린변환나변환▁▁my.ActivityManager::getRunningServices근이있대는기능답활을동투에다입니합거-▁in▁function▁an▁this다▁activity투니입합이기▁put활.

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

언급URL : https://stackoverflow.com/questions/600207/how-to-check-if-a-service-is-running-on-android

반응형