NsdManager doesn't stop service discovery

拜拜、爱过 提交于 2019-12-04 16:07:47

问题


In Android app that I'm currently developing, I want to connect do zero-config networks using NsdManager.

I managed to run network service discovery and connect to the desired network, but after stopping discovery NsdManager thread is still running. This leads to the situation when after a few screen rotations there are many NsdManager threads that are browsing for a connection.

When any network is available, device tries to synchronize many times, so every NsdManager is still active, despite stopping service discovery.

Bellow is my code:

package dtokarzewsk.nsdservicetest;

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

public class NsdTest {
    private static final String NSD_SERVICE_NAME = "TestService";
    private static final String NSD_SERVICE_TYPE = "_http._tcp.";
    private int mPort;
    private InetAddress mHost;
    private Context mContext;
    private NsdManager mNsdManager;
    private android.net.nsd.NsdManager.DiscoveryListener mDiscoveryListener;
    private android.net.nsd.NsdManager.ResolveListener mResolveListener;

    public NsdTest(Context context) {
        mContext = context;
    }

    public void startListening() {
        initializeResolveListener();
        initializeDiscoveryListener();
        mNsdManager = (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
        mNsdManager.discoverServices(NSD_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
    }

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

    private void initializeResolveListener() {
        mResolveListener = new NsdManager.ResolveListener() {
            @Override
            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
                Log.d("NSDService test","Resolve failed");
            }

            @Override
            public void onServiceResolved(NsdServiceInfo serviceInfo) {
                NsdServiceInfo info = serviceInfo;
                Log.d("NSDService test","Resolve failed");
                mHost = info.getHost();
                mPort = info.getPort();
                Log.d("NSDService test","Service resolved :" + mHost + ":" + mPort);
            }
        };
    }

    private void initializeDiscoveryListener() {
        mDiscoveryListener = new NsdManager.DiscoveryListener() {
            @Override
            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
                Log.d("NSDService test","Discovery failed");
            }

            @Override
            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
                Log.d("NSDService test","Stopping discovery failed");
            }

            @Override
            public void onDiscoveryStarted(String serviceType) {
                Log.d("NSDService test","Discovery started");
            }

            @Override
            public void onDiscoveryStopped(String serviceType) {
                Log.d("NSDService test","Discovery stopped");
            }

            @Override
            public void onServiceFound(NsdServiceInfo serviceInfo) {
                NsdServiceInfo info = serviceInfo;
                Log.d("NSDService test","Service found: " + info.getServiceName());
                if (info.getServiceName().equals(NSD_SERVICE_NAME))
                    mNsdManager.resolveService(info, mResolveListener);
            }

            @Override
            public void onServiceLost(NsdServiceInfo serviceInfo) {
                NsdServiceInfo info = serviceInfo;
                Log.d("NSDService test","Service lost: " + info.getServiceName());
            }
        };
    }
}

And in main Activity:

private NsdTest mNsdTest;

@Override
protected void onResume() {
    super.onResume();
    mNsdTest = new NsdTest(this);
    mNsdTest.startListening();
}

@Override
protected void onPause() {
    mNsdTest.stopListening();
    super.onPause();
}

How can I fix this problem?


回答1:


My current solution for this, is to make class containing NsdManager (NsdTest in above example) a singleton with changing context.

It doesn't change the fact that NSdManager thread is constantly running even after stopping service discovery, but at least there is only one active NsdManager thread after resuming application.

Maybe it's not the most elegant way, but is enough for me.

public class NsdTest {

private static NsdTest mInstance;

private static final String NSD_SERVICE_NAME = "TestService";
private static final String NSD_SERVICE_TYPE = "_http._tcp.";
private int mPort;
private InetAddress mHost;
private Context mContext;
private NsdManager mNsdManager;
private android.net.nsd.NsdManager.DiscoveryListener mDiscoveryListener;
private android.net.nsd.NsdManager.ResolveListener mResolveListener;
private static NsdTest mInstance;

private NsdTest(Context context) {
    mContext = context;
}

public static NsdTest getInstance(Context context) {
    if (mInstance == null) {
        mInstance = new NsdTest(context);
    } else {
       mContext = context;
    }
    return mInstance;
}
...}

If anybody knows better solution, please post it.




回答2:


The reason is because NsdManager.stopServiceDiscovery is asynchronous. From the documentation, you must wait for onDiscoveryStopped(String) for the discovery session to actually end.

That you pause immediately after sending the asynchronous request probably means that the callback that would have been triggered got "lost" as your application was in the background. Asynchronous callbacks have a habit of not handling being in the background well.



来源:https://stackoverflow.com/questions/29628181/nsdmanager-doesnt-stop-service-discovery

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!