Kill Network Service Discovery from AsyncTask when done without leaks

339 Views Asked by At

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 //
      }

1

There are 1 best solutions below

0
On

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.