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




android-service (16)

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

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


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)

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


आप इसका उपयोग कर सकते हैं (मैंने अभी तक यह कोशिश नहीं की है, लेकिन मुझे उम्मीद है कि यह काम करता है):

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 विधि घटक घटक ऑब्जेक्ट देता है। यदि नहीं, तो शून्य वापस आ जाएगा।

सार्वजनिक सार घटक Compameentame प्रारंभ सेवा (इरादा सेवा) देखें

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


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

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

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


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

मैंने अभी दो ऐप्स बनाए हैं। पहले ऐप का पैकेज नाम 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


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


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

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

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

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

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


मैं एक गतिविधि के अंदर से निम्नलिखित का उपयोग करता हूं:

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

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


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

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

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

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


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

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


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

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

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

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

मैंने इस एप्लिकेशन का उपयोग अपने आवेदन में इस परिदृश्य को कार्यान्वित करने के तरीके के बारे में जानने के लिए किया था।


समझ गया!

आपको अपनी सेवा के लिए 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;
     }
}

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

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

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

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


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




android-service