(Android)是否有可靠的信号表明网络通道是可路由的?

时间:2015-08-27 23:35:21

标签: android network-programming android-wifi retrofit

我正在开发一个Android应用程序,它定期通过REST API调用报告回数据服务器。每当应用程序尝试发送其中一个报告,但没有可用的网络通道(wifi或移动数据)时,应用程序将为该任务创建一个包装器并将其放入附加到BroadcastReceiver的队列中。接收方侦听android.net.wifi.STATE_CHANGEandroid.net.conn.CONNECTIVITY_CHANGE,然后尝试在新连接上执行排队任务。此处也处理所有身份验证逻辑。实际的请求POST将通过Retrofit库发出。

我的问题是,每当网络访问"回来",并且接收者试图启动所有等待的任务时,我总是回到java.net.UnknownHostException,说明主机数据服务器的名称没有关联的地址。看来,虽然Android设备知道它已连接到网络,但它仍然无法确定从哪里获取DNS,以及任何在此状态下发出的请求会失败。

D/Retrofit﹕ java.net.UnknownHostException: Unable to resolve host "[REDACTED]": No address associated with hostname
        at java.net.InetAddress.lookupHostByName(InetAddress.java:424)
        at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)
        at java.net.InetAddress.getAllByName(InetAddress.java:214)
        at com.squareup.okhttp.internal.Network$1.resolveInetAddresses(Network.java:29)
        at com.squareup.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:266)
        at com.squareup.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:240)
        at com.squareup.okhttp.internal.http.RouteSelector.nextUnconnected(RouteSelector.java:156)
        at com.squareup.okhttp.internal.http.RouteSelector.next(RouteSelector.java:130)
        at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:312)
        at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:235)
        at com.squareup.okhttp.Call.getResponse(Call.java:262)
        at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:219)
        at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:192)
        at com.squareup.okhttp.Call.execute(Call.java:79)
        at retrofit.client.OkClient.execute(OkClient.java:53)
        at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
        at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
        at [REDACTED](Native Method)
        at [REDACTED]
        [etc]
  Caused by: libcore.io.GaiException: getaddrinfo failed: EAI_NODATA (No address associated with hostname)
  Caused by: libcore.io.ErrnoException: getaddrinfo failed: ENETUNREACH (Network is unreachable)

根本原因异常(libcore.io.ErrnoException)声称网络无法访问,但在我收到意图之前,我甚至不尝试执行此操作来自Android OS ,特别是因为网络现在实际上是可以访问的。

我验证无线网络可用性的代码:

protected static boolean isWifiAvailable( WifiManager wifi )
{
    WifiInfo info = wifi.getConnectionInfo() ;
    if( info == null ) return false ;
    if( info.getNetworkId() == -1 ) return false ;
    if( info.getSupplicantState() != SupplicantState.COMPLETED )
        return false ;
    return true ;
}

我的验证移动数据可用性的代码:

protected static boolean isMobileDataAvailable( TelephonyManager tmgr )
{
    return( tmgr.getDataState() == TelephonyManager.DATA_CONNECTED ) ;
}

问题:是否有更可靠的信号 - 我不会在WifiInfoTelephonyManager中检查 - 这表明网络频道是真的,真的准备好了?或者这是一个没有明确解决方案的竞争条件?

1 个答案:

答案 0 :(得分:1)

经常发生我在发布问题后不久就找到了解决方案。事实证明,移动数据检查足够......大部分时间。 wifi检查需要更多工作:

protected static boolean isWifiAvailable( WifiManager wifi )
{
    WifiInfo info = wifi.getConnectionInfo() ;
    if( info == null ) return false ;
    if( info.getNetworkId() == -1 ) return false ;
    if( info.getSupplicantState() != SupplicantState.COMPLETED )
        return false ;
    // Here are the crucial additions:
    DhcpInfo dhcp = wifi.getDhcpInfo() ;
    if( dhcp == null ) return false ;
    if( dhcp.ipAddress != info.getIpAddress() ) return false ;
    return true ;
}

通过WifiInfoDhcpInfo进行检查,我们终于可以确定当前的无线网络是否可路由。