Android设备DiscoveryListener.onServiceFound()调用异常求助
Android NSD服务发现异常:部分设备onServiceFound()无法可靠触发
我的Android应用通过android.net.nsd包实现网络服务器发现功能,98%的设备运行正常,但剩余2%的设备中DiscoveryListener.onServiceFound()无法被可靠调用:
- 受影响设备无明显共性:覆盖Android 9、12等多个版本,涉及Google Pixel 3a、Gigaset GS110等不同品牌机型,路由器包括Fritz!Box、刷OpenWRT的TP-Link等
- 问题与网络环境无关:无论有无互联网连接的网络都可能出现该问题
- 排除连通性故障:同一网络下其他设备可正常发现服务器,受影响设备手动输入IP和端口后也能正常连接服务器
- 简化测试无效:已制作仅保留核心代码的测试应用,受影响设备上
onServiceFound()仍无法可靠调用 - MulticastLock无改善:获取并持有MulticastLock后问题依旧
该服务发现是应用核心功能,需要实现全设备可靠发现。
已添加的权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
MainActivity核心代码
public class MainActivity extends AppCompatActivity { @NonNull private static final String TAG = "MainActivity"; @NonNull private static final String SERVICE_TYPE = "_esu-mrtp._tcp."; @Nullable private NsdManager.DiscoveryListener discoveryListener; @Nullable private NsdManager nsdManager; @Nullable private WifiManager.MulticastLock multicastLock; @Nullable private View viewStarted = null; @Nullable private View viewFound = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.viewStarted = findViewById(R.id.view_started); this.viewFound = findViewById(R.id.view_found); if (null == this.viewStarted || null == this.viewFound) { Toast.makeText(this, "启动失败。", Toast.LENGTH_LONG).show(); } } @Override protected void onStart() { super.onStart(); if (null == this.multicastLock) { WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); if (null != wifiManager) { this.multicastLock = wifiManager.createMulticastLock("multicastLock"); // tag "multicastLock"用于在调试信息中标识该MulticastLock this.multicastLock.setReferenceCounted(true); // 推测refCounted设为false也不会有区别 } else Toast.makeText(this, "无WiFi管理器", Toast.LENGTH_LONG).show();; } if (null != this.multicastLock) this.multicastLock.acquire(); initializeDiscoveryListener(); getNsdManager().discoverServices( SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, this.discoveryListener); } @Override protected void onStop() { super.onStop(); stopServiceDiscovery(); if (null != this.multicastLock) this.multicastLock.release(); } @NonNull private NsdManager getNsdManager() { if (null == this.nsdManager) { this.nsdManager = (NsdManager) getApplicationContext().getSystemService(Context.NSD_SERVICE); if (null == this.nsdManager) Toast.makeText(this, "无NSD管理器!", Toast.LENGTH_LONG).show(); } return this.nsdManager; } private void initializeDiscoveryListener() { if (null == this.discoveryListener) { this.discoveryListener = new NsdManager.DiscoveryListener() { // 服务发现开始时调用 @Override public void onDiscoveryStarted(String regType) { runOnUiThread(() -> { Log.i(TAG, "服务发现已启动"); if (null != viewStarted) viewStarted.setVisibility(View.VISIBLE); }); } @Override public void onServiceFound(NsdServiceInfo service) { runOnUiThread(() -> { // 发现服务!进行后续处理 Log.i(TAG, "服务发现成功" + service); if (service.getServiceType().equals(SERVICE_TYPE)) { if (null != viewFound) viewFound.setVisibility(View.VISIBLE); } }); } @Override public void onServiceLost(NsdServiceInfo service) { runOnUiThread(() -> { // 网络服务不可用时调用 // 此处添加内部记录代码 Log.i(TAG, "服务丢失: " + service); }); } @Override public void onDiscoveryStopped(String serviceType) { runOnUiThread(() -> { Log.i(TAG, "发现已停止: " + serviceType); }); } @Override public void onStartDiscoveryFailed(String serviceType, int errorCode) { runOnUiThread(() -> { Log.i(TAG, "发现失败: 错误代码:" + errorCode); stopServiceDiscovery(); }); } @Override public void onStopDiscoveryFailed(String serviceType, int errorCode) { runOnUiThread(() -> { Log.i(TAG, "发现失败: 错误代码:" + errorCode); stopServiceDiscovery(); }); } }; } } private void stopServiceDiscovery() { if (null == this.discoveryListener) return; getNsdManager().stopServiceDiscovery(this.discoveryListener); this.discoveryListener = null; if (null != this.viewStarted) this.viewStarted.setVisibility(View.INVISIBLE); if (null != this.viewFound) this.viewFound.setVisibility(View.INVISIBLE); } }
内容的提问来源于stack exchange,提问作者Michael Z.
相关产品推荐
相关产品推荐

