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.