I am trying to simply find a device with mDNS, save the IP and kill the "Network Service Discovery"(NSD) once done.
NSD and AsyncTask are in conflict here.
Getting the IP with NSD works but if the AsyncTask is not static it warns of Leaks.
If AsyncTask is static, NSD says from onPostExecute();
Non-static field 'mNsdManager' cannot be referenced from a static context
NSD is still killed from onDestroy if the App exits if i make the AsyncTask static but have to comment out mNsdManager.stopServiceDiscovery( mDiscoveryListener); in onPostExecute() to do it.
With NSD I get the IP in 5-15 seconds but NSD stays seriously busy if i can't kill it if AsyncTask is static.
If i satisfy AsyncTask by making it static mNsdManager complains:
Non-static field 'mNsdManager' cannot be referenced from a static context
The only way i can compile is make AsyncTask non-static and accept the possible leaks -OR- leave AsyncTask static and comment out the KILL line in onPostExecute().
2 ERRORS marked in the code below.
With Android Event based AsyncTask seems the best way, but is it the right way?
How can I kill mNsdManager and still make AsyncTask static to block leaks?
package com.fib.onacci.fibonacci; private static final String TAG = "CLOCK : "; private TextView mIP_address; // NSD members, Allows app to discover the "fibonacci.local" // Reference: // http://developer.android.com/training/connect-devices-wirelessly/nsd.html private static NsdManager mNsdManager; private static NsdManager.DiscoveryListener mDiscoveryListener; private NsdManager.ResolveListener mResolveListener; private NsdServiceInfo mServiceInfo; public String mRPiAddress; public static String IPaddress ="-"; // something to look for change private static final String SERVICE_TYPE = "_http._tcp."; public class MainActivity extends AppCompatActivity { private static final String TAG = "CLOCK: "; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new getIPtoTextView().execute(); // start the AsyncTask // setup nDNS and find IP mRPiAddress = ""; IPaddress = "-"; mNsdManager = (NsdManager)(getApplicationContext().getSystemService(Context.NSD_SERVICE)); initializeResolveListener(); initializeDiscoveryListener(); mNsdManager.discoverServices( SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener); } // END onCreate // NSD start - Network discovery ERROR This AsyncTask class should be static or leaks might occur A static field will leak contexts. private static class getIPtoTextView extends AsyncTask { /** part of nDiscovery - find clock and kill discovery service * `doInBackground` is run on a separate, background thread */ @Override protected Void doInBackground(Void... params) { String mloop = IPaddress; while ( mloop.equals("-")) { mloop = IPaddress; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } Log.i( TAG, "doInBackground - IP Found - " + mloop ); return null; } /** part of nDiscovery * `onPostExecute` is run after `doInBackground`, and it's * run on the main/ui thread, so you it's safe to update ui * components from it. (this is the correct way to update ui * components.) */ @Override protected void onPostExecute(Void param) { Log.i( TAG, "onPostExecute - IP Found - " + IPaddress ); TextView IP_Window = findViewById(R.id.IP_address); IP_Window.setText( IPaddress); // post IP address to TextView ERROR Non-static field 'mNsdManager' cannot be referenced from a static context mNsdManager.stopServiceDiscovery( mDiscoveryListener); // kill mDiscoveryListener } } // end asyncTask class private void initializeDiscoveryListener() { mDiscoveryListener = new NsdManager.DiscoveryListener() { // Listener @Override public void onDiscoveryStarted(String regType) { } @Override public void onServiceFound(NsdServiceInfo service) { // service found! String name = service.getServiceName(); String type = service.getServiceType(); if ( type.equals(SERVICE_TYPE) && name.contains("Fibonacci")) { Log.i( TAG, "\n\tNSD Service Found @ ' " + name + "'"); mNsdManager.resolveService(service, mResolveListener); } } @Override public void onServiceLost(NsdServiceInfo service) { } @Override public void onDiscoveryStopped(String serviceType) { } @Override public void onStartDiscoveryFailed(String serviceType, int errorCode) { mNsdManager.stopServiceDiscovery(this); } @Override public void onStopDiscoveryFailed(String serviceType, int errorCode) { mNsdManager.stopServiceDiscovery(this); } }; } private void initializeResolveListener() { mResolveListener = new NsdManager.ResolveListener(){ @Override public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { Log.i( TAG, "\n\t\tNSD Resolve failed " + errorCode + "\n\n" ); } @Override public void onServiceResolved( NsdServiceInfo serviceInfo ) { mServiceInfo = serviceInfo; InetAddress host = mServiceInfo.getHost(); IPaddress = host.getHostAddress(); mRPiAddress = IPaddress; Log.i( TAG, "\n\t\tNSD Resolved address = " + IPaddress + "\n\n" ); } }; } @Override protected void onPause() { super.onPause(); if ( mDiscoveryListener != null) { mNsdManager.stopServiceDiscovery( mDiscoveryListener); } } @Override protected void onResume() { super.onResume(); if ( mDiscoveryListener != null) { mIP_address.setText( R.string.searching ); // TextView - Searching - try { Thread.sleep( 1500); } catch (InterruptedException e) { e.printStackTrace(); } initializeDiscoveryListener(); } } @Override protected void onDestroy() { super.onDestroy(); mNsdManager.stopServiceDiscovery( mDiscoveryListener); } // NSD end // }
a rewrite was needed because i could not make class getIPtoTextView static without too many errors.
Once i could make class getIPtoTextView static , i moved mNsdManager.stopServiceDiscovery( mDiscoveryListener); to onPause() and onDestroy() all worked fine.