You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:41:18