Android NSD问题:DiscoveryListener回调调用resolveService时mNsdManager为空
问题分析与解决方案
首先看你的空指针问题,根源非常明确:在NSDFinder的startDiscovery方法里,你重新声明了一个局部变量mNsdManager,而不是给类的成员变量赋值。这就导致类里的成员mNsdManager始终是null,当DiscoveryListener的onServiceFound回调触发时,调用mNsdManager.resolveService()自然会抛出空指针异常。
第一步:修复mNsdManager的初始化问题
修改startDiscovery方法,去掉局部变量的声明,直接给成员变量赋值:
public void startDiscovery(Context _c){ mContext = _c; // 去掉前面的NsdManager,直接给类的成员变量赋值 mNsdManager = (NsdManager) _c.getSystemService(Context.NSD_SERVICE); mNsdManager.discoverServices(SERVICE_TYPE, mNsdManager.PROTOCOL_DNS_SD, mDiscoveryListener); }
第二步:关于是否需要继承Service的问题
不需要让NSDFinder继承Service。你感受到的线程/上下文问题,本质是变量作用域和初始化时机的问题,完全不需要依赖Service就能解决。
这里给你几个额外的优化建议,帮你避免后续的坑:
- 建议在
NSDFinder的构造方法里传入Context,而不是在startDiscovery里临时设置,这样能保证mContext和mNsdManager在类初始化时就准备就绪:
然后在MainActivity里初始化时直接传上下文:public NSDFinder(Context context) { mContext = context; mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE); }my_nsdfinder = new NSDFinder(this); - NSD的发现操作最好和页面生命周期绑定,比如在MainActivity的
onPause里停止发现,onResume里按需重启,避免内存泄漏或者不必要的资源消耗:@Override protected void onPause() { super.onPause(); if (my_nsdfinder != null) { my_nsdfinder.stopDiscovery(); } } @Override protected void onResume() { super.onResume(); if (my_nsdfinder != null && !my_nsdfinder.isDiscoveryActive()) { my_nsdfinder.startDiscovery(this); } } - 记得在
NSDFinder里实现stopDiscovery和状态判断方法,避免重复操作或异常:public void stopDiscovery() { if (mNsdManager != null && mDiscoveryListener != null && mDiscoveryActive == 1) { try { mNsdManager.stopServiceDiscovery(mDiscoveryListener); } catch (IllegalArgumentException e) { Log.d(TAG, "Discovery already stopped"); } mDiscoveryActive = 0; } } public boolean isDiscoveryActive() { return mDiscoveryActive == 1; }
第三步:补全ResolveListener的实现
你提供的代码里initializeResolveListener方法不完整,记得补全两个回调的逻辑,比如:
public void initializeResolveListener() { Log.d(TAG, "start initalizing ResolveListener"); mResolveListener = new NsdManager.ResolveListener() { @Override public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { Log.e(TAG, "Resolve failed with code: " + errorCode); // 这里可以添加解析失败的提示逻辑 } @Override public void onServiceResolved(NsdServiceInfo serviceInfo) { Log.d(TAG, "Resolve succeeded: " + serviceInfo); // 在这里获取服务的端口和地址,用于后续连接 mServiceport = serviceInfo.getPort(); mServicehostAdress = serviceInfo.getHost(); } }; }
这样修改后,你的空指针问题应该就能解决,而且不需要把NSD代码放到MainActivity里,也不需要让NSDFinder继承Service,就能保持代码结构清晰。
内容的提问来源于stack exchange,提问作者Niklas Dada
相关产品推荐
相关产品推荐

