2013-01-10 33 views
6

मेरा ऐप किसी अन्य (मेरे) ऐप्स द्वारा प्रदान की जाने वाली सेवा का उपयोग करता है। मैं bound service बुद्धि का उपयोग कर Messenger को एक्सेस करने और इसके साथ संवाद करने के लिए उपयोग कर रहा हूं (और जैसा कि यह एक अलग ऐप है, यह एक दूरस्थ सेवा भी है)।bindService() झूठी रिटर्न देता है लेकिन unbindService() को कॉल करने की आवश्यकता है?

जब मैं एक उचित इरादे से bindService कहते हैं, और कॉल रिटर्न false (जब APK सेवा नहीं के आसपास है प्रदान करने की उम्मीद के रूप में), मैं प्रलेखन और उदाहरण कोड से मान लिया, कि मैं unbind की जरूरत नहीं है ServiceConnection। हालांकि, जब मैं अपने गैलेक्सी नेक्सस (जेली बीन) डिवाइस पर ऐसा कर रहा हूं, तो मुझे Activity को समाप्त करते समय प्रसिद्ध ServiceConnectionLeaked संदेश मिलता है।

मैं

if (!ctxt.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)) { 
    try { 
     ctxt.unbindService(serviceConnection); 
    } catch (Throwable t) {} 
    // Clean up 
    return; 
} 
// Store serviceConnection for future use 

करके बचाया है इस कि मैं कर रहा हूँ उत्सुक: मैं बस दस्तावेज में कुछ वंचित रह गए हैं और यह इस तरह से काम करने के लिए माना जाता है? मैंने try ... catch को यह सुनिश्चित करने के लिए जोड़ा कि यह व्यवहार अन्य उपकरणों या एंड्रॉइड संस्करणों पर वास्तव में अलग है, भले ही मेरा ऐप इससे प्रभावित न हो (नकारात्मक)।

उत्तर

7

सामान्य बोलते हुए, एक सेवा कनेक्शन हमेशा फ्रेमवर्क द्वारा आवंटित और पंजीकृत होता है, भले ही bindService() कॉल वापसी सही या गलत हो। android.app.ContextImpl में bindService() कार्यान्वयन देखें:

public boolean bindService(Intent service, ServiceConnection conn, int flags, int userHandle) { 
    IServiceConnection sd; 
    if (conn == null) { 
     throw new IllegalArgumentException("connection is null"); 
    } 
    if (mPackageInfo != null) { 
     // A new ServiceDispatcher will be created and registered along with 
     // ServiceConnection in LoadedApk.mService for your application context. 
     sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), 
       mMainThread.getHandler(), flags); 
    } else { 
     throw new RuntimeException("Not supported in system context"); 
    } 
    try { 
     ... ... 
     return res != 0; 
    } catch (RemoteException e) { 
     return false; 
    } 
} 

तुम हमेशा सेवा निकल जाना चाहिए जब आप इसके साथ किया जाता है, एक अच्छा प्रोग्रामिंग तरीके के रूप में के रूप में the official dev guide ने सुझाव दिया:

  • डिस्कनेक्ट करने के लिए सेवा से, unbindService() पर कॉल करें।

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

ServiceConnectionLeaked उठाया है जब ढांचा एक अंतिम सफाई करना शुरू कर देते हैं (उदाहरण के लिए, जब आपका एप्लिकेशन से बाहर निकलने जाता है) और पाया कि अपंजीकृत ServiceConnection कर रहे हैं, और फ्रेमवर्क तब आपके लिए इसे अनइंड करने का प्रयास करेगा। removeContextRegistrations() android.app.LoadedApk में देखें कार्यान्वयन:

public void removeContextRegistrations(Context context, 
     String who, String what) { 
    final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled(); 
    ... ... 
    //Slog.i(TAG, "Receiver registrations: " + mReceivers); 
    HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap = 
     mServices.remove(context); 
    if (smap != null) { 
     Iterator<LoadedApk.ServiceDispatcher> it = smap.values().iterator(); 
     while (it.hasNext()) { 
      LoadedApk.ServiceDispatcher sd = it.next(); 
      ServiceConnectionLeaked leak = new ServiceConnectionLeaked(
        what + " " + who + " has leaked ServiceConnection " 
        + sd.getServiceConnection() + " that was originally bound here"); 
      leak.setStackTrace(sd.getLocation().getStackTrace()); 
      Slog.e(ActivityThread.TAG, leak.getMessage(), leak); 
      if (reportRegistrationLeaks) { 
       StrictMode.onServiceConnectionLeaked(leak); 
      } 
      try { 
       ActivityManagerNative.getDefault().unbindService(
         sd.getIServiceConnection()); 
      } catch (RemoteException e) { 
       // system crashed, nothing we can do 
      } 
      sd.doForget(); 
     } 
    } 
    mUnboundServices.remove(context); 
    //Slog.i(TAG, "Service registrations: " + mServices); 
} 
+0

उत्तर के लिए धन्यवाद, लेकिन यह अभी भी नमूने के अनुरूप नहीं है (ApiDemos में जैसे RemoteService भी केवल निकल पड़ता अगर 'onServiceConnected()' कहा जाता था)। हालांकि, आपकी मदद से मैं अब देख सकता हूं कि उच्च स्तर का विवरण भी ऐसी व्याख्या के लिए अनुमति देता है, मैं जवाब स्वीकार करूंगा। – Stephan