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

如何处理Android NSD网络服务发现中的WIFI断开重连问题?

解决NSD服务在WiFi断开重连后无法被发现的问题

我来帮你搞定这个NSD的坑!你遇到的问题其实很常见——WiFi状态切换后,NSD的注册链路容易因为系统网络上下文变化而失效,单纯注销重注册没用,是因为旧的NSD管理器实例或者监听器已经和失效的网络绑定了。下面给你一套可行的解决方案:

核心思路

  1. 监听网络状态变化:在WiFi断开时彻底清理NSD注册,恢复时重新初始化注册流程
  2. 避免复用监听器:每次注册都创建新的RegistrationListener实例,防止旧实例绑定失效的网络上下文
  3. 完善异常处理:处理注销/注册失败的情况,添加重试逻辑提高可靠性

具体实现代码

第一步:添加网络状态监听(用NetworkCallback,适配Android 6.0+)

private ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(@NonNull Network network) {
        super.onAvailable(network);
        // WiFi恢复,触发NSD重新注册
        registerNsdService();
    }

    @Override
    public void onLost(@NonNull Network network) {
        super.onLost(network);
        // WiFi断开,立即注销NSD服务
        unregisterNsdService();
    }
};

// 初始化网络监听
private void initNetworkListener(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (cm != null) {
        cm.registerNetworkCallback(
                new NetworkRequest.Builder()
                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                        .build(),
                networkCallback);
    }
}

第二步:重构NSD注册/注销方法

private void registerNsdService() {
    // 先确保旧的注册已经被清理
    unregisterNsdService();

    NsdServiceInfo serviceInfo = new NsdServiceInfo();
    serviceInfo.setPort(Network.SERVICE_PORT);
    serviceInfo.setServiceName(Network.SERVICE_NAME);
    serviceInfo.setServiceType(Network.SERVICE_TYPE);

    // 每次注册都创建新的监听器,不要复用旧实例!
    Network.registrationListener = new NsdManager.RegistrationListener() {
        @Override
        public void onServiceRegistered(NsdServiceInfo serviceInfo) {
            Intent intent = new Intent(Network.INTENT_SERVICE_REGISTERED);
            LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
        }

        @Override
        public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
            // 注册失败时,延迟3秒重试(可根据需求调整)
            new Handler(Looper.getMainLooper()).postDelayed(() -> registerNsdService(), 3000);
        }

        @Override
        public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
            // 注销成功后,清空监听器引用
            Network.registrationListener = null;
        }

        @Override
        public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
            // 注销失败也清空引用,避免影响后续注册
            Network.registrationListener = null;
            new Handler(Looper.getMainLooper()).postDelayed(() -> registerNsdService(), 3000);
        }
    };

    Network.nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, Network.registrationListener);
}

private void unregisterNsdService() {
    if (Network.nsdManager != null && Network.registrationListener != null) {
        try {
            Network.nsdManager.unregisterService(Network.registrationListener);
        } catch (IllegalArgumentException e) {
            // 如果服务已经被注销,会抛出这个异常,直接忽略即可
            e.printStackTrace();
        }
        Network.registrationListener = null;
    }
}

第三步:在生命周期中绑定监听

在你的Activity/Service的生命周期方法中初始化和清理监听:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 启动网络监听
    initNetworkListener(this);
    // 首次注册NSD服务
    registerNsdService();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // 注销网络监听
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    if (cm != null) {
        cm.unregisterNetworkCallback(networkCallback);
    }
    // 注销NSD服务
    unregisterNsdService();
}

关键注意点

  • 权限配置:别忘了在Manifest中添加必要权限:
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    
  • Android版本适配:如果需要兼容Android 6.0以下,可以改用BroadcastReceiver监听CONNECTIVITY_ACTION(不过官方更推荐用NetworkCallback)
  • 服务名称冲突:如果多次注册后服务名称冲突,可以考虑动态生成服务名称(比如加上设备ID后缀)

内容的提问来源于stack exchange,提问作者Greelings

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:34:29