Android 6.0+ NsdManager报错listener already in use问题求助
问题分析与解决方案
这个报错listener already in use是Android 6.0(API 23)之后NsdManager的行为变更导致的——系统开始严格限制同一个RegistrationListener实例被重复用于服务注册请求,而你的代码恰好存在这个问题:
核心问题点
- 你在
onCreate和onResume中都会调用registerService,且每次都传入同一个mRegistrationListener实例 - Android 6.0之前的系统没有对listener的复用做校验,所以不会报错;但6.0+系统会直接抛出
IllegalArgumentException - 即使你在
onDestroy中调用了unregisterService,但注销是异步操作,如果onResume触发时注销还没完成,再次注册就会冲突
具体修复步骤
1. 添加注册状态跟踪变量
在ServerActivity类中添加一个布尔变量,用来标记当前服务是否处于已注册状态:
public class ServerActivity extends MonitorarSerChamadoActivity { // ... 已有变量 ... private boolean mIsServiceRegistered = false; // 新增状态变量 // ... 剩余代码 ... }
2. 修改registerService方法,避免重复注册
在发起注册前先检查状态,已经注册的话直接返回,避免重复调用:
public void registerService(int port) { // 已注册则跳过,避免重复请求 if (mIsServiceRegistered) { return; } NsdServiceInfo serviceInfo = new NsdServiceInfo(); serviceInfo.setServiceName(SERVICE_NAME); serviceInfo.setServiceType(SERVICE_TYPE); serviceInfo.setPort(port); try { mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener); } catch (Exception e) { e.printStackTrace(); } }
3. 更新RegistrationListener回调,同步状态
在注册/注销的回调中更新状态变量,确保状态始终和实际情况一致:
NsdManager.RegistrationListener mRegistrationListener = new NsdManager.RegistrationListener() { @Override public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) { SERVICE_NAME = NsdServiceInfo.getServiceName(); mIsServiceRegistered = true; // 注册成功,标记状态 } @Override public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { mIsServiceRegistered = false; // 注册失败,重置状态 // 可选:如果是服务名冲突错误(errorCode=NSD_ERROR_SERVICE_NAME_CONFLICT),可以修改服务名后重试 } @Override public void onServiceUnregistered(NsdServiceInfo serviceInfo) { mIsServiceRegistered = false; // 注销完成,重置状态 } @Override public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { mIsServiceRegistered = false; // 注销失败,也重置状态 } };
4. 调整onResume中的注册逻辑
只在服务未注册的情况下才发起注册,避免每次onResume都触发:
@Override protected void onResume() { super.onResume(); if (mNsdManager != null && !mIsServiceRegistered) { registerService(SERVICE_Port); } }
5. 确保权限配置正确(额外提醒)
虽然你排查过权限问题,但还是要确保Manifest中已经添加了NSD所需的权限:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" />
为什么这样修复?
通过状态变量跟踪注册状态,我们确保同一时间只有一个注册请求在使用mRegistrationListener,完全符合Android 6.0+系统对NsdManager的限制。同时异步回调同步状态的逻辑,也能处理注销未完成就进入onResume的边缘情况。
内容的提问来源于stack exchange,提问作者Anderson Scherdovski
相关产品推荐
相关产品推荐

