Listener already in use (Service Discovery)
Asked Answered
K

3

18

I can't resolve one service while another is being resolved? If that's what the error means... What is the way to wait until it is resolved?

@Override
public void onServiceFound(NsdServiceInfo service) {
    Log.d(TAG, "Service found. " + service);
    if (service.getServiceType().equals(SERVICE_TYPE)) {
        if (service.getServiceName().contains(mServiceName)) {
            mNsdManager.resolveService(service, mResolveListener);
        }
    }
}

java.lang.IllegalArgumentException: listener already in use at android.net.nsd.NsdManager.resolveService(NsdManager.java:613) at com.example.miguel.broadcast.LocalService$2.onServiceFound(LocalService.java:145)

Kraken answered 12/9, 2014 at 19:8 Comment(5)
Maybe your issue is related to this reported bug? code.google.com/p/android/issues/detail?id=56830Cajole
@Cajole I'm using Android L and I didn't get this error never.Kraken
Ever find a solution? I get this error too on my lollipop device but not my other devices.Monosymmetric
@tastypython Kind of... I did a workaround. Error is always triggered when using one of the conditions (I wish I can be more helpful here), try to remove or change one and it'll finally work. I deleted my project some time ago, sorry! Read the example code from Google, it helps a lot.Kraken
Thanks for the response, even the sample app from google is broken, and I have since switched to jmdns. I suppose Google's nsd API is not well developed.Monosymmetric
N
27

You don't have to wait! If you look at the javadocs for resolveService(NsdServiceInfo serviceInfo, NsdManager.ResolveListener listener) here you'll notice that for the parameter listener it say's "to receive callback upon success or failure. Cannot be null. Cannot be in use for an active service resolution."

Therefore in order for this to work just do the following:

mNsdManager.resolveService(service, new MyResolveListener());

Where MyResolveListener is:

private class MyResolveListener implements NsdManager.ResolveListener {
        @Override
        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
            //your code
        }

        @Override
        public void onServiceResolved(NsdServiceInfo serviceInfo) {
            //your code
        }
    }

hope this helps :)

Nicholenicholl answered 23/12, 2014 at 16:50 Comment(1)
Hey, thanks for the answer. I don't even remember how I fixed this, but now it would be useful for the Internet now! ;)Kraken
P
15

I had this problem as well, and had been following the Android NsdHelper implementation laid out in NsdChat here. This example shows creating a single NsdManager.ResolveListener mResolveListener in the NsdHelper class, and using that ResolveListener for all calls to NsdManager.resolveService.

From here I read that "a separate Listener is to be used for each active registration or discovery request".

So instead of using a class variable mResolveListener, create a new listener every time you call mNsdManager.resolveService:

@Override
public void onServiceFound(NsdServiceInfo serviceInfo) {
    Log.d(TAG, "Service found: "+ serviceInfo);
    if (serviceInfo.getServiceType().equals(SERVICE_TYPE)){
        mNsdManager.resolveService(serviceInfo, new NsdManager.ResolveListener() {
            @Override
            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
                Log.e(TAG, "Resolve Failed: " + serviceInfo);
            }
            @Override
            public void onServiceResolved(NsdServiceInfo serviceInfo) {
                Log.i(TAG, "Service Resolved: " + serviceInfo);
            }
        });
    }
}
Psychedelic answered 31/12, 2014 at 19:3 Comment(0)
M
7

You need to ensure that you are not passing in a listener object that has already been registered. You can see the commit that resulted in this behavior change here.

Here is the commit message text:

Document and enforce "one request per Listener" rule

The API and implementation of NsdManager imply that a separate Listener is to be used for each active registration or discovery request. This isn't formally documented or properly enforced, and weird and unpredictable things happen if an application uses a Listener for more than one request at a time.

Update documentation to make this an explicit requirement.

Enforce the restriction when a new request is submitted for processing; if the Listener is already being used to track an active request, throw an exception.

Document the fact that apps should unregister services and cancel service discoveries when the app is stopped (in KitKat and prior releases, they'll leak if this isn't done.)

Re-order "release the Listener" operation to occur before the Listener callback, so that the Listener can be reused by the application once the callback has been entered - this eliminates a race condition. Document this.

Pass 2: typos, added documentation about API level, changed to using an explicitly defined return value for "busy listener".

Also, just a warning that if you downloaded the NsdChat sample project from the Android Developers site (i.e. NsdChat.zip or something along those lines), that project code is likely out of date.

Try using the latest code on the master branch instead... you can copy and paste it into your sample project from here.

Madelainemadeleine answered 30/1, 2016 at 23:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.