Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/189.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android NSdManager ResolveListener错误代码3:故障已处于活动状态_Android_Bonjour_Zeroconf_Nsd_Nsdmanager - Fatal编程技术网

Android NSdManager ResolveListener错误代码3:故障已处于活动状态

Android NSdManager ResolveListener错误代码3:故障已处于活动状态,android,bonjour,zeroconf,nsd,nsdmanager,Android,Bonjour,Zeroconf,Nsd,Nsdmanager,我正在安卓应用程序中使用NsdManager来发现另一台同样由我开发的设备发布的NSD服务。我只在Android应用程序上进行服务发现(这方面不需要服务注册)。网络上同时发布了多个相同类型服务的实例 我开始使用Google()提供的示例代码,但由于同时为多个服务解析重用同一个解析器对象,因此出现了致命错误。 然后我发现有几个人建议每次创建一个新的解析器对象(如中) 我这样做了,致命错误被解析失败错误代码3替换,这意味着解析过程处于活动状态。比以前更好,但由于此故障,仅解决了第一个服务,而忽略了其

我正在安卓应用程序中使用NsdManager来发现另一台同样由我开发的设备发布的NSD服务。我只在Android应用程序上进行服务发现(这方面不需要服务注册)。网络上同时发布了多个相同类型服务的实例

我开始使用Google()提供的示例代码,但由于同时为多个服务解析重用同一个解析器对象,因此出现了致命错误。 然后我发现有几个人建议每次创建一个新的解析器对象(如中)

我这样做了,致命错误被解析失败错误代码3替换,这意味着解析过程处于活动状态。比以前更好,但由于此故障,仅解决了第一个服务,而忽略了其余服务

然后我发现一个人建议对错误代码3进行特殊处理,递归地重新发送解析请求,直到它最终被解析()

我在Kotlin中实现了这个解决方案,它可以正常工作,但我并不满意,因为:

  • 我相信我正在创建很多额外的解析器对象 我也不确定他们以后是否会被垃圾收集
  • 我在一个循环中重试了几次,可能会导致额外的 对设备和网络造成不必要的负担。不知道我是否 应该在再次调用服务解析之前添加一个短睡眠
  • 如果出现网络问题,程序可能会尝试数千次 解决同一服务而不是放弃服务的时间 解析并等待再次发现服务
  • RxBonjour2的人们提供了一个更复杂、更强大的解决方案,但它太复杂了,我无法遵循:

    我对谷歌的官方例子没有正确处理这些问题感到沮丧。nsd_chat示例使用单个解析器对象,并且在网络上以相同类型发布多个相同类型的服务时失败

    你能提出更好的解决方案吗?或者对我下面的代码进行任何改进

    import android.app.Application
    import android.content.Context
    import android.net.nsd.NsdManager
    import android.net.nsd.NsdServiceInfo
    import androidx.lifecycle.AndroidViewModel
    import timber.log.Timber
    
    
    class ViewModel(application: Application) : AndroidViewModel(application) {
    
        // Get application context
        private val myAppContext: Context = getApplication<Application>().applicationContext
    
        // Declare DNS-SD related variables for service discovery
        var nsdManager: NsdManager? = null
        private var discoveryListener: NsdManager.DiscoveryListener? = null
    
        // Constructor for the View Model that is run when the view model is created
        init {
    
            // Initialize DNS-SD service discovery
            nsdManager = myAppContext.getSystemService(Context.NSD_SERVICE) as NsdManager?
    
            initializeDiscoveryListener()
    
            // Start looking for available services in the network
            nsdManager?.discoverServices(NSD_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
    
        }
    
        // Instantiate DNS-SD discovery listener
        // used to discover available Sonata audio servers on the same network
        private fun initializeDiscoveryListener() {
    
            // Instantiate a new DiscoveryListener
            discoveryListener = object : NsdManager.DiscoveryListener {
    
                override fun onDiscoveryStarted(regType: String) {
                    // Called as soon as service discovery begins.
                    Timber.d("Service discovery started: $regType")
                }
    
                override fun onServiceFound(service: NsdServiceInfo) {
                    // A service was found! Do something with it
                    Timber.d("Service discovery success: $service")
                    when {
                        service.serviceType != NSD_SERVICE_TYPE ->
                            // Service type is not the one we are looking for
                            Timber.d("Unknown Service Type: ${service.serviceType}")
                        service.serviceName.contains(NSD_SERVICE_NAME) ->
                            // Both service type and service name are the ones we want
                            // Resolve the service to get all the details
                            startResolveService(service)
                        else ->
                            // Service type is ours but not the service name
                            // Log message but do nothing else
                            Timber.d("Unknown Service Name: ${service.serviceName}")
                    }
                }
    
                override fun onServiceLost(service: NsdServiceInfo) {
                    onNsdServiceLost(service)
                }
    
                override fun onDiscoveryStopped(serviceType: String) {
                    Timber.i("Discovery stopped: $serviceType")
                }
    
                override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
                    Timber.e("Start Discovery failed: Error code: $errorCode")
                    nsdManager?.stopServiceDiscovery(this)
                }
    
                override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
                    Timber.e("Stop Discovery failed: Error code: $errorCode")
                    nsdManager?.stopServiceDiscovery(this)
                }
            }
        }
    
        fun startResolveService(service: NsdServiceInfo) {
    
            val newResolveListener =  object : NsdManager.ResolveListener {
    
                override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
                    // Called when the resolve fails. Use the error code to determine action.
                    when (errorCode) {
                        NsdManager.FAILURE_ALREADY_ACTIVE -> {
                            // Resolver was busy
                            Timber.d("Resolve failed: $serviceInfo - Already active")
                            // Just try again...
                            startResolveService(serviceInfo)
                        }
                        else ->
                            Timber.e("Resolve failed: $serviceInfo - Error code: $errorCode")
                    }
                }
    
                override fun onServiceResolved(serviceInfo: NsdServiceInfo) {
                    onNsdServiceResolved(serviceInfo)
                }
            }
    
            nsdManager?.resolveService(service, newResolveListener)
        }
    
        companion object {
    
            // We'll only search for NDS services of this type
            const val NSD_SERVICE_TYPE: String = "_servicetype._tcp."
            // and whose names start like this
            const val NSD_SERVICE_NAME: String = "ServiceName-"
        }
    
        override fun onCleared() {
            try {
                nsdManager?.stopServiceDiscovery(discoveryListener)
            } catch (ignored: Exception) {
                // "Service discovery not active on discoveryListener",
                // thrown if starting the service discovery was unsuccessful earlier
            }
            Timber.d("onCleared called")
            super.onCleared()
        }
    
        fun onNsdServiceResolved(serviceInfo: NsdServiceInfo) {
            // Logic to handle a new service
            Timber.d("Resolve Succeeded: $serviceInfo")
        }
    
        fun onNsdServiceLost(service: NsdServiceInfo) {
            // Logic to handle when the network service is no longer available
            Timber.d("Service lost: $service")
        }
    
    }
    
    导入android.app.Application
    导入android.content.Context
    导入android.net.nsd.NsdManager
    导入android.net.nsd.NsdServiceInfo
    导入androidx.lifecycle.AndroidViewModel
    进口木材
    类ViewModel(应用程序:应用程序):AndroidViewModel(应用程序){
    //获取应用程序上下文
    private val myAppContext:Context=getApplication().applicationContext
    //为服务发现声明DNS-SD相关变量
    变量nsdManager:nsdManager?=null
    私有变量discoveryListener:NsdManager.discoveryListener?=null
    //创建视图模型时运行的视图模型的构造函数
    初始化{
    //初始化DNS-SD服务发现
    nsdManager=myAppContext.getSystemService(Context.NSD_服务)是否作为nsdManager?
    initializeDiscoveryListener()
    //开始在网络中查找可用的服务
    nsdManager?.discoverServices(NSD_服务_类型,nsdManager.PROTOCOL_DNS_SD,discoveryListener)
    }
    //实例化DNS-SD发现侦听器
    //用于发现同一网络上可用的Sonata音频服务器
    private fun initializeDiscoveryListener(){
    //实例化一个新的DiscoveryListener
    discoveryListener=对象:NsdManager.discoveryListener{
    重写onDiscoveryStarted(regType:String){
    //在服务发现开始时立即调用。
    Timber.d(“服务发现已启动:$regType”)
    }
    覆盖fun OnServiceFund(服务:NsdServiceInfo){
    //找到一个服务!用它做点什么
    Timber.d(“服务发现成功:$Service”)
    什么时候{
    service.serviceType!=NSD_服务_类型->
    //服务类型不是我们正在寻找的类型
    d(“未知服务类型:${Service.serviceType}”)
    service.serviceName.contains(NSD\U服务\U名称)->
    //服务类型和服务名称都是我们想要的
    //解析服务以获取所有详细信息
    startResolveService(服务)
    其他->
    //服务类型是我们的,但不是服务名称
    //记录消息,但不执行其他操作
    Timber.d(“未知服务名称:${Service.serviceName}”)
    }
    }
    覆盖服务OST(服务:NsdServiceInfo){
    onNsdServiceLost(服务)
    }
    override fun onDiscoveryStopped(服务类型:字符串){
    Timber.i(“发现停止:$serviceType”)
    }
    重写onStartDiscoveryFailed(服务类型:String,错误代码:Int){
    Timber.e(“启动发现失败:错误代码:$errorCode”)
    nsdManager?.stopServiceDiscovery(此)
    }
    覆盖onStopDiscoveryFailed(服务类型:字符串,错误代码:Int){
    Timber.e(“停止发现失败:错误代码:$errorCode”)
    nsdManager?.stopServiceDiscovery(此)
    }
    }
    }
    趣味startResolveService(服务:NsdServiceInfo){
    val newResolveListener=对象:NsdManager.ResolveListener{
    重写onResolveFailed(serviceInfo:NsdServiceInfo,错误代码:Int){
    //解析失败时调用。使用错误代码确定操作。
    何时(错误代码){
    NsdManager.FAILURE\u已处于活动状态->{
    //解析程序很忙
    Timber.d(“解决失败:$serviceInfo-已激活”)
    //再试一次。。。
    startResolveService(服务信息)
    
    import android.content.Context
    import android.net.nsd.NsdManager
    import android.net.nsd.NsdServiceInfo
    import timber.log.Timber
    import java.util.*
    import java.util.concurrent.ConcurrentLinkedQueue
    import java.util.concurrent.atomic.AtomicBoolean
    import kotlin.collections.ArrayList
    
    abstract class NsdHelper(val context: Context) {
    
        // Declare DNS-SD related variables for service discovery
        val nsdManager: NsdManager? = context.getSystemService(Context.NSD_SERVICE) as NsdManager?
        private var discoveryListener: NsdManager.DiscoveryListener? = null
        private var resolveListener: NsdManager.ResolveListener? = null
        private var resolveListenerBusy = AtomicBoolean(false)
        private var pendingNsdServices = ConcurrentLinkedQueue<NsdServiceInfo>()
        var resolvedNsdServices: MutableList<NsdServiceInfo> = Collections.synchronizedList(ArrayList<NsdServiceInfo>())
    
        companion object {
    
            // Type of services to look for
            const val NSD_SERVICE_TYPE: String = "_myservicetype._tcp."
            // Services' Names must start with this
            const val NSD_SERVICE_NAME: String = "MyServiceName-"
        }
    
        // Initialize Listeners
        fun initializeNsd() {
            // Initialize only resolve listener
            initializeResolveListener()
        }
    
        // Instantiate DNS-SD discovery listener
        // used to discover available Sonata audio servers on the same network
        private fun initializeDiscoveryListener() {
    
            // Instantiate a new DiscoveryListener
            discoveryListener = object : NsdManager.DiscoveryListener {
    
                override fun onDiscoveryStarted(regType: String) {
                    // Called as soon as service discovery begins.
                    Timber.d("Service discovery started: $regType")
                }
    
                override fun onServiceFound(service: NsdServiceInfo) {
                    // A service was found! Do something with it
                    Timber.d("Service discovery success: $service")
    
                    if ( service.serviceType == NSD_SERVICE_TYPE &&
                            service.serviceName.startsWith(NSD_SERVICE_NAME) ) {
                        // Both service type and service name are the ones we want
                        // If the resolver is free, resolve the service to get all the details
                        if (resolveListenerBusy.compareAndSet(false, true)) {
                            nsdManager?.resolveService(service, resolveListener)
                        }
                        else {
                            // Resolver was busy. Add the service to the list of pending services
                            pendingNsdServices.add(service)
                        }
                    }
                    else {
                        // Not our service. Log message but do nothing else
                        Timber.d("Not our Service - Name: ${service.serviceName}, Type: ${service.serviceType}")
                    }
                }
    
                override fun onServiceLost(service: NsdServiceInfo) {
                    Timber.d("Service lost: $service")
    
                    // If the lost service was in the queue of pending services, remove it
                    var iterator = pendingNsdServices.iterator()
                    while (iterator.hasNext()) {
                        if (iterator.next().serviceName == service.serviceName)
                            iterator.remove()
                    }
    
                    // If the lost service was in the list of resolved services, remove it
                    synchronized(resolvedNsdServices) {
                        iterator = resolvedNsdServices.iterator()
                        while (iterator.hasNext()) {
                            if (iterator.next().serviceName == service.serviceName)
                                iterator.remove()
                        }
                    }
    
                    // Do the rest of the processing for the lost service
                    onNsdServiceLost(service)
                }
    
                override fun onDiscoveryStopped(serviceType: String) {
                    Timber.i("Discovery stopped: $serviceType")
                }
    
                override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
                    Timber.e("Start Discovery failed: Error code: $errorCode")
                    stopDiscovery()
                }
    
                override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
                    Timber.e("Stop Discovery failed: Error code: $errorCode")
                    nsdManager?.stopServiceDiscovery(this)
                }
            }
        }
    
        // Instantiate DNS-SD resolve listener to get extra information about the service
        private fun initializeResolveListener() {
            resolveListener =  object : NsdManager.ResolveListener {
    
                override fun onServiceResolved(service: NsdServiceInfo) {
                    Timber.d("Resolve Succeeded: $service")
    
                    // Register the newly resolved service into our list of resolved services
                    resolvedNsdServices.add(service)
    
                    // Process the newly resolved service
                    onNsdServiceResolved(service)
    
                    // Process the next service waiting to be resolved
                    resolveNextInQueue()
                }
    
                override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
                    // Called when the resolve fails. Use the error code to debug.
                    Timber.e("Resolve failed: $serviceInfo - Error code: $errorCode")
    
                    // Process the next service waiting to be resolved
                    resolveNextInQueue()
                }
            }
        }
    
        // Start discovering services on the network
        fun discoverServices() {
            // Cancel any existing discovery request
            stopDiscovery()
    
            initializeDiscoveryListener()
    
            // Start looking for available audio channels in the network
            nsdManager?.discoverServices(NSD_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
        }
    
        // Stop DNS-SD service discovery
        fun stopDiscovery() {
            if (discoveryListener != null) {
                try {
                    nsdManager?.stopServiceDiscovery(discoveryListener)
                } finally {
                }
                discoveryListener = null
            }
        }
    
        // Resolve next NSD service pending resolution
        private fun resolveNextInQueue() {
            // Get the next NSD service waiting to be resolved from the queue
            val nextNsdService = pendingNsdServices.poll()
            if (nextNsdService != null) {
                // There was one. Send to be resolved.
                nsdManager?.resolveService(nextNsdService, resolveListener)
            }
            else {
                // There was no pending service. Release the flag
                resolveListenerBusy.set(false)
            }
        }
    
        // Function to be overriden with custom logic for new service resolved
        abstract fun onNsdServiceResolved(service: NsdServiceInfo)
    
        // Function to be overriden with custom logic for service lost
        abstract fun onNsdServiceLost(service: NsdServiceInfo)
    }
    
    import android.app.Application
    import android.content.Context
    import android.content.Intent
    import android.net.ConnectivityManager
    import android.net.nsd.NsdServiceInfo
    import androidx.lifecycle.AndroidViewModel
    import timber.log.Timber
    import java.util.*
    
    
    class MyViewModel(application: Application) : AndroidViewModel(application) {
    
        // Get application context
        private val myAppContext: Context = getApplication<Application>().applicationContext
    
        // Declare NsdHelper object for service discovery
        private val nsdHelper: NsdHelper? = object : NsdHelper(myAppContext) {
    
            override fun onNsdServiceResolved(service: NsdServiceInfo) {
                // A new network service is available
    
                // Put your custom logic here!!!
    
            }
    
            override fun onNsdServiceLost(service: NsdServiceInfo) {
                // A network service is no longer available
    
                // Put your custom logic here!!!
    
            }
        }
    
        // Block that is run when the view model is created
        init {
    
            // Initialize DNS-SD service discovery
            nsdHelper?.initializeNsd()
    
            // Start looking for available audio channels in the network
            nsdHelper?.discoverServices()
    
        }
    
        // Called when the view model is destroyed
        override fun onCleared() {
            nsdHelper?.stopDiscovery()
            Timber.d("onCleared called")
            super.onCleared()
        }
    
    }