Listener already in use (Service Discovery)

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

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


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.