Android पर कोई सेवा चल रही है या नहीं, इसकी जांच कैसे करें?


936

अगर पृष्ठभूमि सेवा चल रही है तो मैं कैसे जांच करूं?

मुझे एक एंड्रॉइड गतिविधि चाहिए जो सेवा की स्थिति को जन्म देती है - यह मुझे इसे चालू करने की अनुमति देती है यदि यह चालू है और बंद है।



17
सही उत्तर नीचे दिया गया है, न कि एक चिह्नित: stackoverflow.com/a/5921190/2369122
toidiu

1
@toidiu यदि वह पहले से ही पसंद नहीं किया गया है getRunningTasks(), तो यह शायद होगा।
केविन क्रुमविडे

getSystemService () फ़ंक्शन का उपयोग करके आप सभी चल रही सेवाओं को पुनः प्राप्त कर सकते हैं। इसके माध्यम से लूप करें और अपनी सेवा की जाँच करें सूची में मौजूद है यहां आप एक छोटा सा नमूना देख सकते हैं wiki.workassis.com/android-check-the-service-is-running
बिकेश एम

जवाबों:


292

मुझे एक ही समस्या बहुत पहले नहीं थी। चूंकि मेरी सेवा स्थानीय थी, इसलिए मैंने राज्य के टॉगल करने के लिए सेवा क्षेत्र में एक स्थिर क्षेत्र का उपयोग करके समाप्त कर दिया, जैसा कि हैकबॉड ने यहां बताया है

EDIT (रिकॉर्ड के लिए):

यहाँ समाधान है hackbod द्वारा प्रस्तावित:

यदि आपका क्लाइंट और सर्वर कोड समान .apk का हिस्सा है और आप एक ठोस इरादे के साथ सेवा में बंध रहे हैं (एक जो सटीक सेवा वर्ग को निर्दिष्ट करता है), तो आप बस अपनी सेवा को एक वैश्विक चर सेट कर सकते हैं जब वह चल रहा हो आपका ग्राहक जाँच कर सकता है।

हमारे पास जानबूझकर यह जांचने के लिए एपीआई नहीं है कि कोई सेवा चल रही है या नहीं, क्योंकि बिना किसी असफलता के, जब आप कुछ ऐसा करना चाहते हैं, जिससे आप अपने कोड में दौड़ की स्थिति समाप्त कर लें।


27
@ स्पेसर, आपके द्वारा संदर्भित समाधान को सेवा शुरू करने की आवश्यकता है और मुझे लगता है कि सबसे अच्छा लचीला समाधान आपको यह जांचने की अनुमति देना चाहिए कि क्या कोई सेवा शुरू किए बिना चल रही है।
टॉम

17
यदि सिस्टम द्वारा सेवा बंद कर दी जाती है, तो आप कैसे पहचानते हैं और अपने चर को टॉगल करते हैं?
jmng

23
जब ऐप को मार दिया जाता है, तो जिस सेवा को शुरू किया गया था वह भी मार दिया जाता है लेकिन सेवा onDestroy()को कॉल नहीं किया जाता है। तो स्थैतिक चर को ऐसे परिदृश्य में अद्यतन नहीं किया जा सकता है जिसके परिणामस्वरूप असंगत व्यवहार होता है।
फैज़ल

5
@faizal स्टैटिक वैरिएबल को भी पुन: अक्षुण्ण नहीं किया जाएगा, इस प्रकार इसे डिफ़ॉल्ट मान पर वापस सेट किया जाता है जो इंगित करता है कि सेवा अब नहीं चल रही है?
पाब्लो

12
@ हाइफ़ल, स्थानीय सेवा एक अलग प्रक्रिया नहीं है, इसलिए यदि सेवा को मार दिया जाता है, तो ऐप भी मार देगा।
गंभीर

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)

यह मज़बूती से काम करता है, क्योंकि यह ऐक्टिविटी मैनजर # getRunningServices के माध्यम से एंड्रॉइड ऑपरेटिंग सिस्टम द्वारा प्रदान की गई सेवाओं के बारे में जानकारी पर आधारित है ।

OnDestroy या onSometing इवेंट्स या Binders या स्टैटिक वैरिएबल का उपयोग करने वाले सभी दृष्टिकोण मज़बूती से काम नहीं करेंगे क्योंकि एक डेवलपर के रूप में आप कभी नहीं जानते हैं, जब एंड्रॉइड आपकी प्रक्रिया को मारने का फैसला करता है या जिसमें से कॉलबैक को कॉल किया जाता है या नहीं। कृपया एंड्रॉइड डॉक्यूमेंट में जीवनचक्र इवेंट टेबल में "किलएबल" कॉलम को नोट करें ।


85
इस समाधान के लिए धन्यवाद। मैं जोड़ना चाहूंगा: इसके बजाय "com.example.MyService" MyService.class.getName ()
peter.bartos

10
व्यक्तिगत रूप से, मैं एक स्थिर क्षेत्र का उपयोग करके चला गया। यद्यपि getRunningServices () का उपयोग करना अधिक मजबूत समाधान है, मेरा मानना ​​है कि इन दो समाधानों में मजबूती और दक्षता / सादगी के बीच एक व्यापार है। यदि आपको बार-बार जांचने की आवश्यकता है कि क्या कोई सेवा चल रही है, तो संभावित 30+ रनिंग सेवाओं के माध्यम से लूपिंग बहुत आदर्श नहीं है। सिस्टम द्वारा नष्ट की जा रही सेवा के दुर्लभ मामले को शायद एक कोशिश / पकड़ ब्लॉक या START_STICKY का उपयोग करके नियंत्रित किया जा सकता है।
रोबगिनेंस

80
नहीं, यह सही उत्तर नहीं है क्योंकि यह डॉक्स में भी लिखा है: "ध्यान दें: यह विधि केवल डिबगिंग या सेवा प्रबंधन प्रकार उपयोगकर्ता इंटरफ़ेस को लागू करने के लिए है।" यह नियंत्रण प्रवाह के लिए नहीं है!
seb

40
लोगों को यह जानने के लिए कि एक सर्वर चल रहा है की जाँच करने के लिए सभी के माध्यम से जाना सुरुचिपूर्ण लगता है?
रुई मार्केस

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

यह सिर्फ सिस्टम सेवाओं को सूचीबद्ध करेगा, नहीं ?! इसलिए मेरी स्थानीय सेवा को सूची से बाहर रखा गया है और मैं गलत हो जाऊंगा;
इवोक

यदि आप चला रहे हैं, तो स्थानीय सेवाओं के लिए यह बाहरी सेवाओं के साथ काम करता है।
केविन पार्कर

11
क्षमा करें, लेकिन मुझे यह कहने की आवश्यकता है कि सुपर मूर्खतापूर्ण उत्तर है। यह सुपर स्पष्ट क्यों है ?!
Ewoks

10
यहाँ क्या मतलब है स्पष्ट नहीं है ... कौन दुर्घटनाग्रस्त होने के बारे में बात कर रहा था ?! मैं इसे क्रैश करने में दिलचस्प नहीं हूं। सेवा को शुरू किया जा सकता है, रोका जा सकता है, शायद यह इरादे की सेवा थी और ऐसा होने पर यह खुद ही बंद हो जाएगा ... सवाल यह है कि यह कैसे जाना जाए कि यह अभी भी चल रहा है या नहीं उदाहरण के लिए 3 मिनट के बाद।
इवोक

1
यह धारणा देना गलत है कि एक बाध्य सेवा भी शुरू की जानी चाहिए। नहीं। बिंद ऑटो बनाने वाले इसे कहते हैं। यदि सेवा अभी तक नहीं चल रही है तो यह सेवा (और इसलिए "प्रारंभ") बनाएगी।
श्रीदेवी 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

यह समाधान सुरुचिपूर्ण है, लेकिन यह केवल तभी प्रासंगिक है जब आपके पास सेवा वर्ग तक पहुंच हो और केवल कक्षाओं के लिए ही सेवा के ऐप / पैकेज के पास हो। यदि आपकी कक्षाएं सर्विस ऐप / पैकेज से बाहर हैं तो आप एक्टिविटी मैनजर को क्वेरी कर सकते हैं, जो कि पीयर-जान वान रॉज़ द्वारा रेखांकित सीमाओं के साथ है।


32
यह त्रुटिपूर्ण है। onDestroy कहलाने की गारंटी नहीं है।
3

8
जब सिस्टम मेमोरी पर कम होता है, तो आपकी सेवा आपके onDestroy को कॉल किए बिना स्वचालित रूप से मार दी जाएगी, यही कारण है कि मैं कहता हूं कि यह त्रुटिपूर्ण है।
पचेरियर

17
@ स्पेसर, लेकिन अगर सिस्टम प्रक्रिया को मारता है, तो इंस्टेंस फ्लैग को फिर भी रीसेट किया जाएगा। मैं अनुमान लगा रहा हूं कि जब रिसीवर आगे लोड हो जाता है (सिस्टम को सेवा को मारते हुए पोस्ट करता है) स्टेटिक फ्लैग 'इंस्टेंस' को शून्य के रूप में फिर से बनाया जाएगा।
टॉम

2
IsMyServiceRunning में उन सभी सेवाओं के माध्यम से पुनरावृत्ति करने से कम से कम बेहतर है जो वास्तव में सामान को नष्ट कर देता है अगर हर डिवाइस रोटेशन पर किया जाता है :)
गुन्नार फोर्सग्रेन - मोबिमेशन

1
आपके उदाहरण चर को अंतिम घोषित नहीं किया जाना चाहिए, अन्यथा इसे onCreate () या onDestroy () विधियों द्वारा सेट या अशक्त नहीं किया जा सकता है।
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 ऑब्जेक्ट देता है। यदि नहीं, तो शून्य वापस कर दिया जाएगा।

देखें सार्वजनिक सार ComponentName startService (आशय सेवा)

यह मेरे विचार से जाँच जैसा नहीं है, क्योंकि यह सेवा शुरू कर रहा है, इसलिए आप stopService(someIntent);कोड के तहत जोड़ सकते हैं ।


11
डॉक्स का कहना बिल्कुल नहीं। आपके लिंक के अनुसार: "रिटर्न यदि सेवा शुरू हो रही है या पहले से चल रही है, तो शुरू की गई वास्तविक सेवा का घटक नाम वापस आ गया है, अन्यथा यदि सेवा मौजूद नहीं है तो अशक्त लौटा दी जाती है।"
गैब्रियल

अच्छी सोच ... लेकिन वर्तमान स्थिति में फिट नहीं है।
कोड_लिफ़

5
इसका उचित तरीका नहीं है, क्योंकि जब IDE ट्रिगर if(startService(someIntent) != null)जो कि जाँच करेगा IsserviceRunningलेकिन वह भी नई सेवा चलाएगा।
चिंतन क्रिया

जैसा कि कहा गया है, यदि आप इस नियंत्रण के बाद सेवा को रोक देते हैं तो यह इस समस्या के लिए उपयोगी होगा। लेकिन बिना किसी सेवा के शुरू करने और रोकने के लिए क्यों?
तानकर

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 । जब से हम तुल्यकालिक प्रसारित कर सकते हैं, हम प्रसारण और एक परिणाम प्राप्त कर सकते हैं तुल्यकालिक यूआई धागे पर,।

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()क्योंकि यह बहुत सरल है।


यह स्वीकार किए गए से बेहतर समाधान है, जो विफल हो जाता है अगर एंड्रॉइड सेवा को मारता है क्योंकि वैश्विक चर विधि अभी भी इंगित करेगी कि सेवा तब चल रही है जब यह वास्तव में नहीं है। यह तुल्यकालिक पिंग-पोंग प्रसारण चाल वास्तव में सेवा की जाँच करने के लिए केवल विश्वसनीय तरीका है अगर कोई सेवा जीवित है। यह अकेले ही आपको ASK सेवा की अनुमति देता है यदि यह वहां है। यदि यह उत्तर देता है तो सेवा जीवित है और चल रही है, यदि नहीं तो यह या तो शुरू नहीं किया गया है या बंद कर दिया गया है, या तो प्रोग्रामेटिक रूप से या सिस्टम द्वारा मेमोरी को पुनर्प्राप्त करने के लिए।
फीनिक्सरिव्ड

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<? extends Service>
silentsudo

11

यह जांचने का उचित तरीका है कि कोई सेवा चल रही है या नहीं। अपनी सेवा में एक ब्रॉडकास्टर को लागू करें जो आपकी गतिविधियों से पिंग्स के प्रति प्रतिक्रिया करता है। जब सेवा शुरू होती है, तब ब्रॉडकास्टसीवर को पंजीकृत करें और सेवा के नष्ट होने पर उसे अनरजिस्टर्ड करें। अपनी गतिविधि (या किसी भी घटक) से, सेवा के लिए एक स्थानीय प्रसारण आशय भेजें और यदि यह जवाब देता है, तो आप जानते हैं कि यह चल रहा है। नीचे दिए गए कोड में 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
मुझे वास्तव में यह दृष्टिकोण पसंद है। यह थोड़ा भारी कोड वार है लेकिन हमेशा काम करेगा। मुझे प्रसारण के इरादे जल्द ही किसी भी समय पदावनत होते नहीं दिख रहे हैं :)
शेल्डुडे

8

मैं सिर्फ @Snicolas द्वारा उत्तर में एक नोट जोड़ना चाहता हूं। निम्नलिखित चरणों का उपयोग कॉल के साथ / बिना कॉल सेवा को रोकने के लिए किया जा सकता है onDestroy()

  1. onDestroy() कहा जाता है: सेटिंग्स पर जाएं -> एप्लिकेशन -> रनिंग सर्विसेज -> अपनी सेवा का चयन करें और बंद करें।

  2. onDestroy()कॉल नहीं किया गया: सेटिंग्स पर जाएं -> एप्लिकेशन -> एप्लिकेशन प्रबंधित करें -> चयन करें और अपने एप्लिकेशन को "फोर्स स्टॉप" जिसमें आपकी सेवा चल रही है। हालाँकि, जैसा कि आपका एप्लिकेशन यहां रोक दिया गया है, इसलिए निश्चित रूप से सेवा इंस्टेंसेस को भी रोक दिया जाएगा।

अंत में, मैं यह उल्लेख करना चाहूंगा कि एकल वर्ग में एक स्थिर चर का उपयोग करते हुए वहां वर्णित दृष्टिकोण मेरे लिए काम कर रहा है।


7

onDestroy हमेशा सेवा में नहीं बुलाया जाता है इसलिए यह बेकार है!

उदाहरण के लिए: बस ग्रहण से एक परिवर्तन के साथ ऐप को फिर से चलाएं। एप्लिकेशन को SIG: 9 का उपयोग करके बलपूर्वक बाहर कर दिया जाता है।


6

सबसे पहले आप गतिविधि प्रबंधक का उपयोग करके सेवा तक पहुँचने की कोशिश नहीं करेंगे। ( यहां चर्चा की गई )

सेवाएँ अपने आप चल सकती हैं, एक गतिविधि या दोनों के लिए बाध्य हो सकती हैं। किसी गतिविधि में जाँच करने का तरीका अगर आपकी सेवा चल रही है या नहीं है, तो एक इंटरफ़ेस बनाकर (जो बिंदर का विस्तार करता है) जहाँ आप उन तरीकों की घोषणा करते हैं जो गतिविधि और सेवा दोनों को समझते हैं। आप अपना स्वयं का इंटरफ़ेस बनाकर ऐसा कर सकते हैं जहाँ आप उदाहरण के लिए "isServiceRunning ()" की घोषणा करते हैं। फिर आप अपनी गतिविधि को अपनी सेवा से जोड़ सकते हैं, विधि isServiceRunning () चला सकते हैं, सेवा स्वयं के लिए जाँच करेगी कि यह चल रहा है या नहीं और आपकी गतिविधि के लिए एक बूलियन वापस करता है।

आप अपनी सेवा को रोकने या किसी अन्य तरीके से इसके साथ सहभागिता करने के लिए भी इस पद्धति का उपयोग कर सकते हैं।

मैंने इस ट्यूटोरियल का उपयोग अपने आवेदन में इस परिदृश्य को लागू करने के लिए सीखने के लिए किया।


3
वह चर्चा '12 / 26/07 'पर हुई। या तो इस वर्ष की जुलाई (भविष्य में) है, या इससे पहले कि एंड्रॉइड भी सार्वजनिक था। किसी भी तरह से जो मुझे इस पर भरोसा नहीं करता है।
टॉम

यह चर्चा 26 दिसंबर, 2007 से है। वे एक पूर्व-रिलीज़ संस्करण पर विचार कर रहे हैं, जो मुझे लगता है ( डेवलपर .
android.com/sdk/OLD_RELEASENOTES.html#m3-rc37a

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
संयुक्त या अपने पिछले उत्तर को अपडेट करें। कृपया प्रति पोस्ट एक से अधिक उत्तर देने से बचें।
चुआनपहम

क्या इस उत्तर का विस्तार किया जा सकता है, अर्थात सेवा के साथ CODE के लिए कोई मूल्य कैसे संबद्ध करता है?
डेव नट

प्रसंग कहाँ से लाएँ?
तुलसी

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

इसके साथ एकमात्र समस्या यह है कि सेवा एक स्टिकी सेवा है और यह स्वयं को पुनरारंभ करता है। IsServiceCreated () को कॉल करना सेवा के फिर से शुरू होने के बाद गलत हो जाएगा क्योंकि mInstance शून्य हो जाएगा।
मीरा_काले

1
OnCreate को तब नहीं बुलाया जाएगा जब सेवा स्वयं को पुनः आरंभ करती है?
at:५३ पर atealChx101

6

ज़मारिन सी # संस्करण:

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

आपको teContext` की आवश्यकता है GetSystemService
परीक्षण

5

यहां दिए गए उपयोग-मामले के लिए हम केवल stopService()विधि के रिटर्न मान का उपयोग कर सकते हैं । trueयदि निर्दिष्ट सेवा मौजूद है और यह मारा जाता है तो यह वापस आ जाता है। इसे वापस कर देता है false। तो आप सेवा को फिर से शुरू कर सकते हैं यदि परिणाम कुछ falseऔर है तो यह आश्वासन दिया जाता है कि वर्तमान सेवा बंद कर दी गई है। :) इस पर एक नज़र डालें तो बेहतर होगा ।


5

कोटलिन का उपयोग करते हुए एक और दृष्टिकोण। अन्य उपयोगकर्ताओं के उत्तर में प्रेरित

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

कोटलिन में आप साथी ऑब्जेक्ट में बूलियन वैरिएबल जोड़ सकते हैं और किसी भी वर्ग से उसके मूल्य की जांच कर सकते हैं जो आप चाहते हैं:

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

कोटलिन के लिए, आप नीचे दिए गए कोड का उपयोग कर सकते हैं।

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
}

परीक्षण लिखने के लिए यह एक शानदार उत्तर है, क्योंकि आप इसका उपयोग अपने कामकाजी कोड को बदले बिना कर सकते हैं।
रॉबर्ट लिबरेट

2

गीक की प्रतिक्रिया लेकिन कोटलिन वर्ग में। धन्यवाद 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एंड्रॉइड ओ के बाद से पदावनत किया जाता है
डैनियल शटज़

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तुलना करना है। और एक डिवाइस पर एक ही पैकेज नाम के साथ दो ऐप नहीं हो सकते।

के बराबर () विधि 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;
}

घटक का नाम


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

यह इंटेंट सर्विस डिबगिंग की ओर अधिक लागू होता है क्योंकि वे एक धागा बनाते हैं, लेकिन नियमित सेवाओं के लिए भी काम कर सकते हैं। मुझे यह धागा बिंगिंग के लिए धन्यवाद मिला

मेरे मामले में, मैंने डिबगर के साथ खेला और थ्रेड दृश्य पाया। यह एमएस वर्ड में बुलेट पॉइंट आइकन की तरह दिखता है। वैसे भी, आपको इसका उपयोग करने के लिए डीबगर मोड में होना आवश्यक नहीं है। प्रक्रिया पर क्लिक करें और उस बटन पर क्लिक करें। जब भी वे चल रहे हों, कम से कम एमुलेटर पर तो कोई भी इंटेंट सेवा दिखाई नहीं देगी।


0

यदि सेवा किसी अन्य प्रक्रिया से संबंधित है या एपीकेएडमैनजर पर आधारित समाधान का उपयोग करती है।

यदि आपके पास इसके स्रोत तक पहुंच है, तो स्थैतिक क्षेत्र के आधार पर समाधान का उपयोग करें। लेकिन एक बूलियन का उपयोग करने के बजाय मैं एक दिनांक ऑब्जेक्ट का उपयोग करने का सुझाव दूंगा। जबकि सेवा चल रही है, बस इसके मान को 'अभी' तक अपडेट करें और जब यह समाप्त हो जाए तो इसे शून्य पर सेट करें। गतिविधि से आप जांच सकते हैं कि क्या इसकी अशक्तता या तारीख बहुत पुरानी है जिसका मतलब है कि यह नहीं चल रहा है।

आप अपनी सेवा से प्रसारण अधिसूचना भी भेज सकते हैं जो यह बताती है कि प्रगति जैसी जानकारी के साथ चल रहा है।


0

अंदर TheServiceClass को परिभाषित:

 public static Boolean serviceRunning = false;

तब ऑनस्टार्टकमांड (...) में

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

    serviceRunning = true;
    ...
}

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

} 

फिर, if(TheServiceClass.serviceRunning == true)किसी भी वर्ग से कॉल करें ।


4
यह काम नहीं करता है यदि आप सेवा एंड्रॉइड द्वारा मार दी जाती है।
हाइजेनबर्ग

@ हेइसेनबर्ग मैं सिर्फ अपने आप को अनुभव करता हूं। जानते हो क्यों नहीं?
टिम

@ हायसेनबर्ग जब मेरे ऐप को ओएस द्वारा मार दिया जाता है, तो सेवा फिर से शुरू होती है और स्थिर बूल को सच कर देती है, लेकिन इसे प्राप्त करने पर यह गलत रिपोर्ट करता है
टिम

यदि आप कॉल करते हैं तो यह काम नहीं करेगा stopService। कम से कम इंटेंट सेवाओं के लिए। onDestroy()तुरंत बुलाया जाएगा, लेकिन onHandleIntent()अभी भी चल रहा होगा
serggl

1
@ हाइजेनबर्ग कम स्मृति के कारण सेवा की हत्या नहीं करेंगे, इसका मतलब यह है कि प्रक्रिया को मारना है?
Android डेवलपर

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.

नोट: यह विधि केवल डिबगिंग या सेवा प्रबंधन प्रकार उपयोगकर्ता इंटरफ़ेस को लागू करने के लिए है।


ps। Android प्रलेखन भ्रामक है मैंने किसी भी संदेह को खत्म करने के लिए Google ट्रैकर पर एक मुद्दा खोला है:

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

जैसा कि हम बाइंड सेवा देख सकते हैं, वास्तव में सर्विस कैश बाइंडर्स के माध्यम से एक्टिविटी मैनेजर बाइंडर के माध्यम से लेन-देन को आमंत्रित करता है - मैं ट्रैक करता हूं कि कौन सी सेवा बाध्यकारी के लिए जिम्मेदार है लेकिन जैसा कि हम देख सकते हैं कि बाइंड के लिए परिणाम है:

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

यह ActivThread में इसके द्वारा सेट किया गया है:

 public final void bindApplication(...) {

        if (services != null) {
            // Setup the service cache in the ServiceManager
            ServiceManager.initServiceCache(services);
        }

इसे MethodManagerService विधि में कहा जाता है:

 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 झांकना सेवा (इरादे सेवा, स्ट्रिंग संकल्प टाइप, स्ट्रिंग कॉलपेकेज) 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 पद्धति का रिटर्न मान) असत्य नहीं है।
स्वेगेथ सिवन

0

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

-2

एंड्रॉइड डेवलपर विकल्पों में से इस विकल्प का उपयोग करना आपके लिए यह देखना संभव है कि क्या आपकी सेवा अभी भी पृष्ठभूमि में चल रही है।

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
केवल तभी कोई भी आपके लिए मूल्य को अपडेट नहीं करेगा जब वे सेवा को मार देंगे
गुन्नार फोर्सग्रेन - मोबिमेशन

जब सेवा को मार डालो onDestroy () शुरू हो जाएगा और कहा कि अपने राज्य को अद्यतन करने के लिए संभव है
Jongz Puangput

5
@JongzPuangput, onDestroyसेवा के मारे जाने पर हमेशा नहीं बुलाया जाता है। उदाहरण के लिए, मैंने अपनी सेवाओं को कम मेमोरी स्थितियों में बिना मारे onDestroyबुलाया देखा है।
सैम

@ ससम तो क्या कहलायेगा?
रुचिर बरोनिया

2
@ रुचिरबनिया जहाँ तक मुझे याद है, आपके सामान के मारे जाने पर आपको बस सूचना नहीं मिलती है। मेरा मानना ​​है कि एंड्रॉइड को आवश्यकतानुसार एप्लिकेशन को मारने के लिए डिज़ाइन किया गया है, और एप्लिकेशन को बिना सूचना के किसी भी बिंदु पर मारे जाने की उम्मीद करने के लिए डिज़ाइन किया जाना चाहिए।
सैम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.