I want to exchange data between android devices, therefore NSD should be used to find other devices. I followed the example on Android Developers
The service is registered successfully on the network by the server-device, the client-device recognize the service and enter the discoveryListener callback method onServiceFound(). Then I initialize the resolveListener and call resolveService(), but the app crashes with
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.net.nsd.NsdManager.resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager$ResolveListener)' on a null object reference
at de.niklasdahlheimer.oboeapitest.oboeapitest.NSDFinder$1.onServiceFound(NSDFinder.java:59)
at android.net.nsd.NsdManager$ServiceHandler.handleMessage(NsdManager.java:333)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.os.HandlerThread.run(HandlerThread.java:61)
My mNsdManager is not null in the NSDFinder class but somehow it is null in the callback-methods of the DiscoveryListener. Seems like I have a problem with different threads or a missunderstanding in working with contexts. Should my NSDFinder class extend service or something? I do not want the NSD-Code in the main-activity to keep the code well structured.
(shortened) main Activity
public class MainActivity extends AppCompatActivity {
//Variable Declarations
NSDFinder my_nsdfinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
button_discoverserver =(Button) findViewById(R.id.button_discoverServer);
//Variables Instantiations
my_nsdfinder = new NSDFinder();
button_discoverserver.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
my_nsdfinder.initializeDiscoveryListener();
my_nsdfinder.startDiscovery(getApplicationContext());
Toast.makeText(getApplicationContext(),"Suche nach Servern...",Toast.LENGTH_LONG).show();
}
});
}
}
NSDFinder class (NSDFinder.java)
public class NSDFinder{
String TAG = "NSDFINDER";
NsdManager mNsdManager;
NsdManager.DiscoveryListener mDiscoveryListener;
String mServiceName;
String SERVICE_TYPE = "_http._tcp.";
Context mContext;
int mDiscoveryActive = 0;
FragmentManager m_DialogManager;
NsdManager.ResolveListener mResolveListener;
NsdServiceInfo mService;
int mServiceport;
InetAddress mServicehostAdress;
public void initializeDiscoveryListener() {
// Instantiate a new DiscoveryListener
mDiscoveryListener = new NsdManager.DiscoveryListener() {
// Called as soon as service discovery begins.
@Override
public void onDiscoveryStarted(String regType) {
Log.d(TAG, "Service discovery started");
mDiscoveryActive = 1;
}
@Override
public void onServiceFound(NsdServiceInfo service) {
// A service was found! Do something with it.
Log.d(TAG, "Service discovery success\n" + service);
if (!service.getServiceType().equals(SERVICE_TYPE)) {
// Service type is the string containing the protocol and
// transport layer for this service.
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
} else if (service.getServiceName().equals(mServiceName)) {
// The name of the service tells the user what they'd be
// connecting to. It could be "Bob's Chat App".
Log.d(TAG, "Same machine: " + mServiceName);
} else if (service.getServiceName().contains("LTCTool")){
Toast.makeText(mContext,"LTCTool Server gefunden! "+service,Toast.LENGTH_LONG).show();
initializeResolveListener();
mNsdManager.resolveService(service,mResolveListener);
//mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
}
@Override
public void onServiceLost(NsdServiceInfo service) {
// When the network service is no longer available.
// Internal bookkeeping code goes here.
Log.e(TAG, "service lost" + service);
}
@Override
public void onDiscoveryStopped(String serviceType) {
Log.i(TAG, "Discovery stopped: " + serviceType);
mDiscoveryActive = 0;
}
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}
public void startDiscovery(Context _c){
mContext = _c;
NsdManager mNsdManager = (NsdManager) _c.getSystemService(Context.NSD_SERVICE);
mNsdManager.discoverServices(SERVICE_TYPE, mNsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
public void initializeResolveListener() {
Log.d(TAG, "start initalizing ResolveListener");
mResolveListener = new NsdManager.ResolveListener() {
@Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Called when the resolve fails. Use the error code to debug.
Log.e(TAG, "Resolve failed" + errorCode);
}
@Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same IP.");
return;
}
mService = serviceInfo;
mServiceport = mService.getPort();
mServicehostAdress = mService.getHost();
Toast.makeText(mContext,"Dienstinformationen aufgelöst! Port: "+mServiceport+" Adresse: "+mServicehostAdress,Toast.LENGTH_LONG).show();
}
};
Log.d(TAG, "ResolveListener initialized");
}
}