Error in Android 6.0 NSD service

2

NSD is a service used to discover other applications that run the same service in the local network. I'm trying to make the NSD sample work that it finds in the official Android site .

The problem is that when selecting Search the application falls only on Android 6 (I have a tablet with android 4.4.4 and it does not give the error). When reopening the app the same thing happens. The error is as follows:

java.lang.IllegalStateException: Could not execute method for android:onClick
    at android.view.View$DeclaredOnClickListener.onClick(View.java:4741)
    at android.view.View.performClick(View.java:5698)
    at android.widget.TextView.performClick(TextView.java:10846)
    at android.view.View$PerformClick.run(View.java:22565)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:158)
    at android.app.ActivityThread.main(ActivityThread.java:7230)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
 Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invoke(Native Method)
    at android.view.View$DeclaredOnClickListener.onClick(View.java:4736)
    at android.view.View.performClick(View.java:5698) 
    at android.widget.TextView.performClick(TextView.java:10846) 
    at android.view.View$PerformClick.run(View.java:22565) 
    at android.os.Handler.handleCallback(Handler.java:739) 
    at android.os.Handler.dispatchMessage(Handler.java:95) 
    at android.os.Looper.loop(Looper.java:158) 
    at android.app.ActivityThread.main(ActivityThread.java:7230) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
 Caused by: java.lang.IllegalArgumentException: listener already in use
    at android.net.nsd.NsdManager.discoverServices(NsdManager.java:559)
    at com.miaplicacion.configurador.NsdHelper.discoverServices(NsdHelper.java:140)
    at com.miaplicacion.configurador.NsdChatActivity.clickDiscover(NsdChatActivity.java:58)
    at java.lang.reflect.Method.invoke(Native Method) 
    at android.view.View$DeclaredOnClickListener.onClick(View.java:4736) 
    at android.view.View.performClick(View.java:5698) 
    at android.widget.TextView.performClick(TextView.java:10846) 
    at android.view.View$PerformClick.run(View.java:22565) 
    at android.os.Handler.handleCallback(Handler.java:739) 
    at android.os.Handler.dispatchMessage(Handler.java:95) 
    at android.os.Looper.loop(Looper.java:158) 
    at android.app.ActivityThread.main(ActivityThread.java:7230) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 

I think the main error is because "listener already in use". But I do not know how to solve it.

These are the additional codes:

activity_main.xml (the button code)

<Button
    android:id="@+id/discover_btn"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:onClick="clickDiscover"
    android:text="Buscar" />

NsdChatActivity (the code of the Activity that receives the click event)

public void clickDiscover(View v) {
    mNsdHelper.discoverServices();
}

NsdHelper

public void discoverServices() {
    mNsdManager.discoverServices(
            SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
    
asked by UselesssCat 23.03.2017 в 21:51
source

2 answers

1

The real problem in this example about NSD is:

  

Caused by: java.lang.IllegalArgumentException: listener already in use

What you have to ensure is not to use the same defined listener, for this you can create a class to not use the same instance of the listener:

//mNsdManager.resolveService(service, mResolveListener); //Incorrecto.
mNsdManager.resolveService(service, new MyResolveListener());

The class in question would be:

private class MyResolveListener implements NsdManager.ResolveListener {
    @Override
    public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
        Log.e(TAG, "*Jorgesys Resolve failed" + errorCode);
    }

    @Override
    public void onServiceResolved(NsdServiceInfo serviceInfo) {
        Log.e(TAG, "*Jorgesys Resolve Succeeded. " + serviceInfo);

        if (serviceInfo.getServiceName().equals(mServiceName)) {
            Log.d(TAG, "Same IP.");
            return;
        }
        mService = serviceInfo;
    }
}

I add the full NsdHelper class:

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.nsdchat;

import android.content.Context;
import android.net.nsd.NsdServiceInfo;
import android.net.nsd.NsdManager;
import android.util.Log;

public class NsdHelper {

    Context mContext;

    NsdManager mNsdManager;
    NsdManager.ResolveListener mResolveListener;
    NsdManager.DiscoveryListener mDiscoveryListener;
    NsdManager.RegistrationListener mRegistrationListener;

    public static final String SERVICE_TYPE = "_http._tcp.";

    public static final String TAG = "NsdHelper";
    public String mServiceName = "NsdChat";

    NsdServiceInfo mService;

    public NsdHelper(Context context) {
        mContext = context;
        mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
    }

    public void initializeNsd() {
        //initializeResolveListener();
        //initializeDiscoveryListener();
        //initializeRegistrationListener();
        //mNsdManager.init(mContext.getMainLooper(), this);
    }

    public void registerService(int port) {
        NsdServiceInfo serviceInfo  = new NsdServiceInfo();
        serviceInfo.setPort(port);
        serviceInfo.setServiceName(mServiceName);
        serviceInfo.setServiceType(SERVICE_TYPE);
        mRegistrationListener = new MyRegistrationListener(); //Jorgesys
        mNsdManager.registerService(
                serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);

    }

    public void discoverServices() {
        mDiscoveryListener = new MyDiscoveryListener(); //Jorgesys
        mNsdManager.discoverServices(
                SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
    }

    public void stopDiscovery() {
        mNsdManager.stopServiceDiscovery(mDiscoveryListener);
    }

    public NsdServiceInfo getChosenServiceInfo() {
        return mService;
    }

    public void tearDown() {
        mNsdManager.unregisterService(mRegistrationListener);
    }

    /*** New classes to avoid : java.lang.IllegalArgumentException: listener already in use ***/

    private class MyResolveListener implements NsdManager.ResolveListener {
        @Override
        public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
            Log.e(TAG, "*Jorgesys Resolve failed" + errorCode);
        }

        @Override
        public void onServiceResolved(NsdServiceInfo serviceInfo) {
            Log.e(TAG, "*Jorgesys Resolve Succeeded. " + serviceInfo);

            if (serviceInfo.getServiceName().equals(mServiceName)) {
                Log.d(TAG, "Same IP.");
                return;
            }
            mService = serviceInfo;
        }
    }

    //mDiscoveryListener = new NsdManager.DiscoveryListener() {

    private class MyRegistrationListener implements NsdManager.RegistrationListener {

        @Override
        public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
            mServiceName = NsdServiceInfo.getServiceName();
        }

        @Override
        public void onRegistrationFailed(NsdServiceInfo arg0, int arg1) {
        }

        @Override
        public void onServiceUnregistered(NsdServiceInfo arg0) {
        }

        @Override
        public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
        }
    }

    private class MyDiscoveryListener implements NsdManager.DiscoveryListener {
        @Override
        public void onDiscoveryStarted(String regType) {
            Log.d(TAG, "Service discovery started");
        }

        @Override
        public void onServiceFound(NsdServiceInfo service) {
            Log.d(TAG, "Service discovery success" + service);
            if (!service.getServiceType().equals(SERVICE_TYPE)) {
                Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
            } else if (service.getServiceName().equals(mServiceName)) {
                Log.d(TAG, "Same machine: " + mServiceName);
            } else if (service.getServiceName().contains(mServiceName)){
                mNsdManager.resolveService(service, new MyResolveListener());
            }
        }

        @Override
        public void onServiceLost(NsdServiceInfo service) {
            Log.e(TAG, "service lost" + service);
            if (mService == service) {
                mService = null;
            }
        }

        @Override
        public void onDiscoveryStopped(String serviceType) {
            Log.i(TAG, "Discovery stopped: " + serviceType);
        }

        @Override
        public void onStartDiscoveryFailed(String serviceType, int errorCode) {
            Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            mNsdManager.stopServiceDiscovery(this);
        }

        @Override
        public void onStopDiscoveryFailed(String serviceType, int errorCode) {
            Log.e(TAG, "Discovery failed: Error code:" + errorCode);
            mNsdManager.stopServiceDiscovery(this);
        }

    }
}
    
answered by 24.03.2017 / 01:58
source
1

On the documentation says:

  

NsdManager.DiscoveryListener: The listener notifies of a successful discovery and is used to stop discovery on this serviceType through to call on stopServiceDiscovery (NsdManager.DiscoveryListener). Can not be null. Can not be used for an active service discovery.

The problem seems to be your listener's century of life. Probably the mDiscoveryListener that you spend is already in use. Try creating a Listener by implementing DiscoveryListener that you want and save in discoverServices .

public class MiDiscoveryListener implements DiscoveryListener{
    //...
}

and create it at the moment when you start discovering services.

public void discoverServices() {
    // Solamente tratemos de descubrir servicios si todavía no lo estamos haciendo
    if (null==mDiscoveryListener)
        mDiscoveryListener = new MiDiscoveryListener();
        mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
    }
}
  

The application should call stopServiceDiscovery (NsdManager.DiscoveryListener) when discovery of this service type is not required, and / or whenever the application is paused or stopped.

onStop(){
    super.onStop();
    if (null!=mDiscoveryListener){
        mNsdManager.stopDiscovery(mDiscoveryListener);
        mDiscoveryListener=null;
    }
}

You will probably have to design a little more accurate the life cycles of your activities and when the discovery of services begins.

    
answered by 23.03.2017 в 23:39