android यह जांचें कि एंड्रॉइड पर कोई सेवा चल रही है या नहीं?




android-service (20)

मैं कैसे जांचूं कि पृष्ठभूमि सेवा (एंड्रॉइड पर) चल रही है या नहीं?

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


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

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

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

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


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)

Xamarin सी # verison।

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

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

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

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


मैंने ऊपर प्रस्तुत समाधानों में से एक को थोड़ा संशोधित किया है, लेकिन एक सामान्य विधि वर्ग के बजाय वर्ग को पारित करने के लिए, उसी विधि से बाहर आने वाले तारों की तुलना करना सुनिश्चित करने के लिए 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);

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


नीचे एक सुरुचिपूर्ण हैक है जो सभी 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(...);
    }

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

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


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


    public boolean checkServiceRunning(){
         ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) 
                {
                    if ("com.example.yourpackagename.YourServiceName"
                            .equals(service.service.getClassName())) 
                    {
                        return true;
                    }
                }
             return false;
    }

इसे आसान दोस्तों ले लो ... :)

मुझे लगता है कि सबसे उपयुक्त समाधान 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);
}

कोई विशेष अनुमति नहीं, कोई लूप नहीं ... आसान तरीका, साफ समाधान :)

अगर आपको अतिरिक्त जानकारी चाहिए, तो कृपया link देखें

उम्मीद है की यह मदद करेगा।


public static boolean isServiceRunning;

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
isServiceRunning = true;
return START_NOT_STICKY;
}

@Override
    public void onDestroy() {
        super.onDestroy();
        isServiceRunning = false;
    }

या

यदि स्थैतिक उपयोग नहीं करना चाहते हैं तो उपयोगकर्ता साझा संदर्भ

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    PrefManager.getPref().saveBoolean(AppConstants.Pref.IS_SERVICE_RUNNING, true);
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    PrefManager.getPref().saveBoolean(AppConstants.Pref.IS_SERVICE_RUNNING, false);
}

PrefManager सभी प्राथमिकताओं के प्रबंधन के लिए मेरी सिंगलटन कक्षा है।


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

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


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) कॉल करें।


एक छोटा सा पूरक है:

मेरा लक्ष्य यह जानना है कि एक सेवा चल रही है, अगर यह चल रहा है तो वास्तविक रूप से चल रहा है।

कॉलिंग बाइंड सेवा या सेवा के द्वारा पकड़ा जा सकता है कि एक इरादा बुलाया एक अच्छा विचार नहीं है क्योंकि यह सेवा शुरू नहीं होने पर सेवा शुरू हो जाएगी।

इसलिए, जैसा कि miracle2k ने सुझाव दिया है, सबसे अच्छा यह है कि सेवा कक्षा में एक स्थिर क्षेत्र होना है ताकि यह पता चल सके कि सेवा शुरू हो गई है या नहीं।

इसे और भी क्लीनर बनाने के लिए, मैं सलाह देता हूं कि एक सिंगलटन में सेवा को बहुत ही आलसी आचरण के साथ बदलना है: यानी स्थिर विधियों के माध्यम से सभी singleton उदाहरण में कोई तात्कालिकता नहीं है। आपकी सेवा / सिंगलटन की स्टेटिक 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 से पूछ सकते हैं।


समझ गया!

आपको अपनी सेवा के लिए startService() को उचित रूप से पंजीकृत होने और BIND_AUTO_CREATE को गुजरने के लिए 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;
     }
}

यह एंड्रॉइड दस्तावेज़ों से निकाला गया है

आदेशित प्रसारण ( Context.sendOrderedBroadcast के साथ भेजा गया) एक समय में एक रिसीवर को दिया जाता है। चूंकि प्रत्येक रिसीवर बदले में निष्पादित होता है, यह परिणाम अगले रिसीवर को प्रसारित कर सकता है, या यह प्रसारण पूरी तरह से निरस्त कर सकता है ताकि यह अन्य रिसीवरों को पारित नहीं किया जा सके।

यह एक हैक का थोड़ा सा है, लेकिन इस बारे में सोचें कि Service को "पिंगिंग" के रूप में हम सिंक्रनाइज़ रूप से प्रसारित कर सकते हैं, हम यूआई थ्रेड पर सिंक्रनाइज़ रूप से प्रसारण कर सकते हैं और परिणाम प्राप्त कर सकते हैं।

Service

BroadcastReceiver

@Override
public void onCreate() {
   LocalBroadcastManager
     .getInstance(this)
     .registerReceiver(new ServiceEchoReceiver(), IntentFilter("echo");
}

private class ServiceEchoReceiver{
    public void onReceive (Context context, Intent intent) {
      LocalBroadcastManager
         .getInstance(this)
         .sendBroadcastSync(new Intent("echo"));
    }
}

Activity

    bool serviceRunning = false;

    protected void onCreate (Bundle savedInstanceState){
        LocalBroadcastManager.getInstance(this).registerReceiver(echo);
        LocalBroadcastManager.getInstance(this).sendBroadcastSync(new Intent("echo"));
        if(!serviceRunning){
           //try and run the service
        }
    }

    private BroadcastReceiver echo = new BroadcastReceiver(){
        public void onReceive (Context context, Intent intent) {
          serviceRunning = true;   
        }
    }

एक ही कक्षा के नाम के साथ कई सेवाएं हो सकती हैं।

मैंने अभी दो ऐप्स बनाए हैं। पहले ऐप का पैकेज नाम com.example.mock । मैंने ऐप में Mock2Service नामक एक Mock2Service बनाया और Mock2Service नामक एक सेवा Mock2Service । तो इसका पूर्ण योग्य नाम com.example.mock.lorem.Mock2Service

फिर मैंने दूसरा ऐप और 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 उदाहरणों की तुलना करना एक बेहतर विचार है क्योंकि ComponentName नाम के equals() पैकेज नाम और वर्ग दोनों नामों की तुलना करता है। और डिवाइस पर उसी पैकेज नाम के साथ दो ऐप्स नहीं हो सकते हैं।

ComponentName की बराबर () विधि।

@Override
public boolean equals(Object obj) {
    try {
        if (obj != null) {
            ComponentName other = (ComponentName)obj;
            // Note: no null checks, because mPackage and mClass can
            // never be null.
            return mPackage.equals(other.mPackage)
                    && mClass.equals(other.mClass);
        }
    } catch (ClassCastException e) {
    }
    return false;
}

ComponentName


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

संपादित करें (रिकॉर्ड के लिए):

हैकबोड द्वारा प्रस्तावित समाधान यहां दिया गया है:

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

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


ऑटो का निर्माण न करें - ऑटो देखें - पीएस देखें।

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। एंड्रॉइड प्रलेखन भ्रामक है मैंने किसी भी संदेह को खत्म करने के लिए 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);

यह गतिविधि थ्रेड के माध्यम से सेट है:

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

मेरे पास अब सी में खोदने के लिए समय नहीं है, जब तक कि मैं बाकी कॉल को विच्छेद नहीं करता, मैं अपना जवाब निलंबित करता हूं।

लेकिन जांच के लिए सबसे अच्छा तरीका है कि सेवा चल रही है, बांधने के लिए है (यदि बांध नहीं बनाया गया है सेवा मौजूद नहीं है) - और बांध के माध्यम से अपने राज्य के बारे में सेवा पूछें (इस पर संग्रहीत आंतरिक ध्वज का उपयोग करके)।







android-service