2015-04-14 3 views
15

В приложении Android, которое я сейчас разрабатываю, я хочу подключиться к сетям нуль-конфигурации, используя NsdManager.NsdManager не останавливает обнаружение службы

Мне удалось запустить обнаружение сетевых сервисов и подключиться к нужной сети, но после остановки открытия NsdManager поток все еще работает. Это приводит к ситуации, когда после нескольких поворотов экрана существует много потоков NsdManager, которые просматривают соединение.

enter image description here

Когда любая сеть доступна, устройство пытается синхронизировать много раз, так что каждый NsdManager по-прежнему активен, несмотря на прекращение обнаружения сервисов.

Беллоу мой код:

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

И в главном Activity:

private NsdTest mNsdTest; 

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

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

Как я могу исправить эту проблему?

+0

Вы считаете использование 'WeakReference ' для хранения 'Context'? – Sebastiano

+0

@dextor К сожалению, это ничего не меняет. Тем не менее создается несколько потоков. –

+0

Как вы заключаете, что потоки 'NSDManager' на самом деле все еще выполняют обнаружение mDNS, тем более, что вы упоминаете, что' onDiscoveryStopped' вызывается правильно? Вы видите пакеты mDNS в сниффер? Это может быть так, что обнаружение остановилось, но система сохранила поток вокруг, вероятно, ожидая освобождения некоторых ресурсов, прежде чем, наконец, его убить. – curioustechizen

ответ

5

Мое текущее решение для этого - сделать класс, содержащий NsdManager (NsdTest в приведенном выше примере), синглтон с изменяющимся контекстом.

Это не меняет того факта, что поток NSdManager постоянно работает даже после остановки обнаружения службы, но по крайней мере, есть только один активный поток NsdManager после возобновления приложения.

Возможно, это не самый изящный способ, но для меня этого достаточно.

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

Если кто-нибудь знает лучшее решение, отправьте его.

1

Причина в том, что NsdManager.stopServiceDiscovery является асинхронным. От documentation вы должны дождаться onDiscoveryStopped(String) для завершения сеанса обнаружения.

То, что вы делаете паузу сразу после отправки асинхронного запроса, вероятно, означает, что обратный вызов, который был бы запущен, получил «потерянный», поскольку ваше приложение было в фоновом режиме. Асинхронные обратные вызовы имеют привычку не работать в фоновом режиме.

+1

Это не проблема. onDiscoveryStopped (String) запускается должным образом каждый раз (при каждом повороте экрана). –

+0

По моему мнению, даже если обратный вызов «потерян», открытие все равно должно прекратиться. Другими словами, методы обратного вызова должны быть вызваны после того, как открытие действительно остановится. – curioustechizen

+0

@curioustechizen В идеальном мире, который был бы таким.Но Android делает неудобные вещи, когда вы выполняете асинхронные вызовы, а затем помещаете свое приложение в фоновом режиме. NsdService не мог получить сообщение и, возможно, не имел возможности запустить его, или он попытался запустить его, но, поскольку ваше приложение было в фоновом режиме, некоторые проверки где-то не удались, и он вышел без вашего ведома. У Nsd много гоночных условий, поэтому я немного циничен. – justhecuke