12.1 问题
应用程序需要监控网络连接状态的变化。
12.2 解决方案
(API Level 1)
通过ConnectivityManager监控设备的网络连接设备。在移动应用程序的设计过程中,需要考虑的一个很重要的问题就是网络并不是随时都是连通的。随着人的移动,网络的速度和容量都在不断地变化。正因为如此,使用网络资源的应用程序需要随时监控这些资源是否可访问,并不能访问时通知用户。
除了连通性,ConnectivityManager还能向应用程序提供网络连接的类型。这样就能根据情况决定是否要下载大文件,如果用户处于漫游状态的话,下载大文件会使数据流量暴增。
12.3 实现机制
以下代码清单封装了一个方法,可以把它放到你的代码中来检查网络的连通性。
ConnectivityManager 封装方法
public boolean isNetworkReachable() {
final ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo current = mManager.getActiveNetworkInfo();
if(current == null) {
return false;
}
return (current.getState() == NetworkInfo.State.CONNECTED);
}
ConnectivityManager所做的工作是评估哪个网络数据接口被认为是活跃的(Wi-Fi或蜂窝网络)。在最简单的情况下,我们仅检查给定接口是否已连接。注意:如果没有可用的活跃数据连接,ConnectivityManager.getActiveNetworkInfo()会返回null,所以首先要检查这种情况。如果有可用的网络,就可以检查其状态,可能的返回值如下:
- DISCONNECTED
- CONNTECTING
- CONNECTED
- DISCONNECTING
如果返回的状态是CONNECTED,网络就是稳定的,可以用来访问远程资源。
1. 验证路线
移动设备有多条连接路线(Wi-Fi、3G/4G等),并且设备经常连接到没有外部Web路线的网络;Wi-Fi网络尤其如此。ConnectivityManager仅仅通知用户其设备是否已关联特定的网络,但不会表明该网络是否能够访问外部IP地址。因此,当设备尝试通过已“连接”但没有有效路线的网络进行连接时,网络栈就会花费几分钟的时间超时并适当失败。
在某些情况下,更加智能的方法是检查有效的Internet连接,而非仅检查与网络的关联。以下代码清单以前面的连通性检查为基础,用于检查Internet连接。
更加智能的ConnectivityManager封装方法
public static boolean isNetworkReachable(Context context){
final ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
//如果没有与网络关联,则在此处进行关联
boolean connected = (null != activeNetworkInfo && activeNetworkInfo.isConnected()){
if (!connected) return false;
//检查是否可以访问远程服务器
boolean routeExists;
try{
//检查Google公共DNS
InetAddress host = InetAddress.getByName("8.8.8.8");
Socket s = new Socket();
s.connect(new InetSocketAddress(host,53),5000);
//如果没有抛出异常,则DNS存在
routeExists = true;
s.close();
}catch (IOException e){
routeExists = false;
}
return (connected && routeExists);
}
如往常一样验证相同的连通性条件之后,上面的代码清单进一步尝试打开套接字(具有5秒的超时),该套接字指向Google公共DNS的众所周知的标准IPv4标准(8.8.8.8)。如果成功连接此主机,我们就能够确信设备可以访问任何激活的Internet资源。相比于直接全面连接远程服务器,此方法的优势是代码将更快地失败,强制最多5秒的延迟,然后就立刻告诉用户,我们实际上并没有自认为已具备的Internet连接。
当网络请求失败时,最好检查网络的连通性,告知用户请求失败是网络问题。以下代码清单中的示例演示了如何在网络访问失败时检查网络的连通性。
告知用户网络不通
try{
//尝试访问网络资源时,如果失败,可能会抛出HttpResponseException或其他 IOException
}catch(Exception e){
if( !isNetworkReachable() ){
AlertDialog.Builder builder = new AlertDialog.Builder builder(context);
builder.setTitle("No Network Connection");
builder.setMessage( " The Network is unavailable. "
+ " Please try your request again later. " );
builder.setPositiveButton("OK",null);
builder.create().show();
}
}
2. 判断连接类型
在某些情况下,应用程序还必须知道用户所连接的网络是否是按流量收费的,可以调用活动网络连接的NetworkInfo.getType()方法以获取相关信息(参见以下代码)。
ConnectivityManager带宽检查
public boolean isWifiReachable(){
ConnectivityManager mManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo current = mManager.getActiveNetworkInfo();
if (current == null){
return false;
}
return (current.getType() == ConnectivityManager.TYPE_WIFI);
}
这个修改后的连通性检查版本能够判断用户是否连接到了Wi-Fi网络,如果连接的是Wi-Fi网络,通常就意味着网速比较快,而且流量是免费的。
网友评论