Androidでサービスが実行されているかどうかを確認するにはどうすればよいですか?


936

バックグラウンドサービスが実行されているかどうかを確認するにはどうすればよいですか?

サービスの状態を切り替えるAndroidアクティビティが必要です。これにより、サービスがオフの場合はオンになり、オンの場合はオフにできます。



17
:正解はマーク1を下回るとではありませんstackoverflow.com/a/5921190/2369122
toidiu

1
@toidiuそれがまだのようgetRunningTasks()に神経衰弱していないなら、おそらくそうなるでしょう。
Kevin Krumwiede

getSystemService()関数を使用すると、実行中のすべてのサービスを取得できます。それをループとは、ここであなたが小さなサンプル見ることができるリストであなたのサービスが存在を確認しwiki.workassis.com/android-check-the-service-is-running
Bikesh M

回答:


292

ずっと前に同じ問題がありました。私のサービスはローカルだったので、ここの hackbod 説明されているように、サービスクラスの静的フィールドを使用して状態を切り替えまし

編集(記録用):

これがハックボッドによって提案されたソリューションです:

クライアントとサーバーのコードが同じ.apkの一部であり、具体的なインテント(正確なサービスクラスを指定するもの)を使用してサービスにバインドしている場合は、サービスでグローバル変数を設定するだけで実行できます。クライアントが確認できます。

ほぼ間違いなく、コードで競合状態が発生するようなことをしたいので、サービスが実行されているかどうかを確認するAPIは意図的にはありません。


27
@Pacerier、あなたが参照するソリューションはサービスを開始する必要があります。最高の柔軟なソリューションは、サービスを開始せずにサービスが実行されているかどうかを確認できるはずだと思います。
トム

17
サービスがシステムによって停止されている場合はどうですか、それをどのように検出して変数を切り替えますか?
jmng 2014年

23
アプリが強制終了されると、それが開始していたサービスも強制終了されますが、サービスonDestroy()は呼び出されません。そのため、このようなシナリオでは静的変数を更新できず、動作に一貫性がなくなります。
ファイサル、2014

5
@faizal静的変数も再初期化されないので、サービスが実行されていないことを示すデフォルト値に戻しますか?
PabloC 2014

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イベント、Binder、または静的変数を使用するすべてのアプローチは、Androidがプロセスを強制終了することを決定したとき、または言及されたコールバックのどれが呼び出されるかどうかがわからないため、確実に機能しません。Androidドキュメントのライフサイクルイベントテーブルの「killable」列に注意してください。


85
この解決策をありがとう。追加したい:代わりに "com.example.MyService"はMyService.class.getName()を使用する方がエレガントです
peter.bartos

10
個人的には、静的フィールドを使用しました。getRunningServices()を使用する方がより堅牢なソリューションですが、これら2つのソリューションには、堅牢性と効率性/シンプルさの間のトレードオフがあると思います。サービスが実行されているかどうかを頻繁に確認する必要がある場合、30以上の実行中の可能性のあるサービスをループすることはあまり理想的ではありません。システムによって破壊されるサービスのまれなケースは、おそらくtry / catchブロックによって、またはSTART_STICKYを使用することによって処理できます。
robguinness 2012

80
いいえ、それはドキュメントにも書かれているため、正しい答えではありません。「注:このメソッドは、サービス管理タイプのユーザーインターフェイスのデバッグまたは実装のみを目的としています。」制御フロー用ではありません!
2012

40
サーバーが実行されているかどうかを確認するために、これらすべてを実行する必要があるのはエレガントだと思いますか?
Rui Marques

81
開始AndroidのOをgetRunningServices推奨されていません。この回答には、新しいバージョンのアップデートが必要です。
poring91 2017

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

これは、システムサービスのみを一覧表示します。そのため、私のローカルサービスはリストから除外され、falseが
返され

これは外部サービスで機能します。ローカルサービスは、実行している場合は非常に明白です。
Kevin Parker、

11
申し訳ありませんが、それは非常にばかげた答えだと言う必要があります。
Ewoks 2013年

10
ここであなたが何を意味するのか明確ではありません...クラッシュについて話しているのは誰ですか?クラッシュするのは面白くない。サービスを開始、停止、インテントサービスである可能性があります。サービスが完了すると、サービス自体で停止します...質問は、たとえば3分後にまだ実行中かどうかを確認する方法です。
Ewoks 2013年

1
バインドされたサービスも開始する必要があるという印象を与えるのは誤りです。番号。Bind auto createは、まさにそれを実行します。サービスがまだ実行されていない場合は、サービスを作成(したがって「開始」)します。
Sreedevi J 2017

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 2012年

8
システムのメモリが不足している場合、onDestroyを呼び出さなくてもサービスが自動的に終了します。そのため、これに欠陥があると言います。
パセリエ

17
@Pacerier、ただしシステムがプロセスを強制終了した場合でも、インスタンスフラグはリセットされます。レシーバーが次にロードされたとき(システムがサービスを強制終了した後)、静的フラグ「インスタンス」がnullとして再作成されると思います。
トム

2
isMyServiceRunningでこれらすべてのサービスを反復処理するよりも優れています。デバイスのローテーションごとに行われると、遅延が発生します:)
Gunnar Forsgren-Mobimation 2013

1
インスタンス変数はfinalと宣言しないでください。宣言すると、onCreate()またはonDestroy()メソッドで設定またはnull化できません。
k2col 2013

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(Intent service)を参照してください。

これは、サービスを開始しているのでstopService(someIntent);、コードの下に追加できるので、私が考えるチェックとは異なります。


11
正確にドキュメントが言うことではありません。リンクによれば、「戻り値サービスが開始中または既に実行中の場合は、開始された実際のサービスのComponentNameが返され、サービスが存在しない場合はnullが返されます。」
ガブリエル

いい考えですが、現在の状況には適合しません。
Code_Life 2012

5
IDEトリガーがif(startService(someIntent) != null)それをチェックするときにそれIsserviceRunningが新しいサービスを再生するので、それは適切な方法ではありません。
チンタンケティヤ2013年

既に述べたように、この制御の後でサービスを停止すると、この問題に役立ちます。しかし、なぜ無料でサービスを開始および停止するのでしょうか。
2013

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

もちろん、多くのアプリケーションでの勝者は、truein Service.onCreate()and to falseinに設定されているサービスの静的ブールフィールドService.onDestroy()です。


これは、受け入れられたものよりもはるかに優れたソリューションです。Androidがサービスを強制終了すると失敗します。グローバル変数メソッドは、サービスが実際には停止しているときにサービスが実行中であることを示すためです。この同期ピンポンブロードキャストトリックは、実際には、サービスが生きているかどうかを確認する唯一の信頼できる方法です。それだけで、サービスがある場合は単にサービスに質問することができます。応答した場合、サービスはアクティブで実行中です。サービスが開始されていないかシャットダウンされている場合は、プログラムまたはシステムによってメモリを回復します。
フェニックス

13

上記の解決策の1つを少し変更しましたが、同じメソッドから出てくる文字列を確実に比較するために、一般的な文字列名の代わりにクラスを渡します。 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<? extends Service>
silentsudo

11

サービスが実行されているかどうかを確認する適切な方法は、単にそれを尋ねることです。アクティビティからの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;
            }
        }
    };
}

1
私は実際にこのアプローチが好きです。少し重いコードですが、常に機能します。ブロードキャストインテントがすぐに廃止される予定はありません:)
ShellDude

8

@Snicolasの回答にメモを追加したいだけです。次の手順を使用して、を呼び出して、または呼び出さずにサービスの停止を確認できますonDestroy()

  1. onDestroy() 呼び出し:設定->アプリケーション->実行中のサービス->選択してサービスを停止します。

  2. onDestroy()呼び出されない:設定->アプリケーション->アプリケーションの管理->サービスが実行されているアプリケーションを選択して「強制停止」します。ただし、ここでアプリケーションが停止すると、サービスインスタンスも確実に停止します。

最後に、シングルトンクラスで静的変数を使用する方法について説明します。


7

onDestroy サービスで常に呼び出されるとは限らないため、これは役に立ちません!

たとえば、Eclipseから1つの変更を加えて、アプリを再度実行するだけです。アプリケーションはSIGを使用して強制的に終了します:9。


6

まず最初に、ActivityManagerを使用してサービスにアクセスしようとしないでください。(ここで議論)

サービスは単独で実行することも、アクティビティにバインドすることも、その両方を行うこともできます。サービスが実行されているかどうかをアクティビティにチェックインする方法は、アクティビティとサービスの両方が理解するメソッドを宣言するインターフェイス(バインダーを拡張する)を作成することです。これを行うには、たとえば「isServiceRunning()」などを宣言する独自のインターフェースを作成します。次に、アクティビティをサービスにバインドし、メソッドisServiceRunning()を実行します。サービスは、サービスが実行中かどうかをチェックし、ブール値をアクティビティに返します。

このメソッドを使用して、サービスを停止したり、別の方法でサービスと対話したりすることもできます。

このチュートリアルを使用して、このシナリオをアプリケーションに実装する方法を学びました。


3
その議論は「2007年12月26日」に行われた。それは今年の7月(つまり、将来)であるか、Androidが公開される前でもあります。どちらにしても、私はそれを信用できなくなります。
トム

その議論がある12月26日、彼らは私が考えるプレリリースバージョン(議論されている2007年からdeveloper.android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a 12月14日、2007年にリリースされました)
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
以前の回答を組み合わせるか更新します。1つの投稿に複数の回答を投稿することはご遠慮ください。
ChuongPham 2014年

この答えは拡張できますか、つまり、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(...);
    }

これに関する唯一の問題は、サービスがスティッキーサービスであり、サービスが再起動するかどうかです。mServiceがnullになるため、サービスの再開後にisServiceCreated()を呼び出すとfalseが返されます。
Mira_Cole

1
その後、サービスが自動的に再起動するときにonCreateが呼び出されませんか?
TheRealChx101

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

コトリン拡張として

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

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)

6
ActivityManager.getRunningServicesAndroid Oから廃止されました
Daniel Shatz

1

同じクラス名を持つ複数のサービスが存在する可能性があります。

2つのアプリを作成しました。最初のアプリのパッケージ名はcom.example.mockです。loremアプリで呼び出されるサブパッケージとというサービスを作成しましたMock2Service。したがって、その完全修飾名はcom.example.mock.lorem.Mock2Serviceです。

次に、2番目のアプリとというサービスを作成しましたMock2Service。2番目のアプリのパッケージ名は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ます。また、同じパッケージ名の2つのアプリをデバイスにインストールすることはできません。

の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オブジェクトを使用することをお勧めします。サービスの実行中に、その値を「今」に更新し、終了したらnullに設定します。アクティビティから、その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によってサービスが停止された場合、これは機能しません。
ハイゼンベルク

@ハイゼンベルク私はちょうどそれを自分で経験しました。なぜだか分かりますか?
Tim

@Heisenberg私のアプリがOSによって強制終了されると、サービスは再起動し、静的ブール値をtrueに設定しますが、取得するとfalseを報告します
Tim

これはを呼び出しても機能しませんstopService。少なくともIntentサービスの場合。onDestroy()すぐに呼び出されますが、onHandleIntent()まだ実行中です
serggl

1
@Heisenbergメモリ不足のためにサービスを強制終了しないと、プロセスも強制終了されますか?
Android開発者

0

bindを単純に使用して、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.

注:このメソッドは、サービス管理タイプのユーザーインターフェイスのデバッグまたは実装のみを目的としています。


ps。Androidのドキュメントが誤解を招く疑いを解消するために、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;
}

要するに :)

「すでにバインドされているサービスにバインダーを提供します。このメソッドは同期的であり、存在しない場合はターゲットサービスを開始しません。」

public IBinder peekService(Intent service、String resolveType、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;
}

*


bindResult(bindServiceメソッドの戻り値)は、サービスが実行されていない場合はfalseになりません。
Shangeeth Sivan 2017

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 Developerオプションのこのオプションを使用して、サービスがバックグラウンドで実行されているかどうかを確認できます。

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、サービスが実行されているかどうかに関係なく、キーと値のペアを保持することです。

論理は非常にまっすぐです。サービスクラスの任意の位置。サービスが実行されているかどうかについてのフラグとして機能するブール値を入力します。次に、この値をアプリケーションの任意の場所で読み取ります。

私のアプリで使用しているサンプルコードは以下のとおりです。

私のServiceクラス(Audio Streamのサービス)では、サービスが稼働しているときに次のコードを実行します。

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 '30 / 07/30

サービスをkillするとonDestroy()がトリガーされ、その状態を更新できます
Jongz Puangput 2015

5
@JongzPuangput onDestroyは、サービスが終了したときに常に呼び出されるわけではありません。たとえば、サービスonDestroyが呼び出されずにメモリ不足の状況で終了するのを見てきました。
Sam

@サムそれでは何が呼ばれますか?
Ruchir Baronia 2016

2
@RuchirBaronia私が覚えている限り、あなたの物が殺されたときにあなたは単に通知されません。Androidは必要に応じてアプリを強制終了するように設計されていると思います。アプリは通知なしでいつでも強制終了されることを想定して設計する必要があります。
サム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.