10.1.2 联网方式的选择

在Android应用中通过org.apache.http等Java包去连接互联网,并不需要关注设备的具体联网方式,这是因为Android系统会自动托管对联网方式的管理和选择。

Android支持通过GPRS、CDMA、WiMAX、WiFi等多种方式连接网络(每种联网方式的实现,都需要相应的底层设备和驱动支持),在每种联网模式下,都会有一些可供选择的连接点(Access Point)。每一个连接点,都包含一系列具体的联网设置,包括网关地址、连接密码、代理服务,等等。依据这些配置信息,Android可以通过不同的联网方式访问互联网服务。

如果一个连接点在当前环境中可用,即可以根据这些配置连接上网络,便称该连接点为可用连接点。系统可以通过任意一个可用连接点连接网络,但不同的连接点意味着不同的连接速度和花费开销。如何从众多可用连接点中选择最合适的来连接网络?Symbian等传统的移动操作系统将这个选择题抛给了开发者和用户,让他们根据自己的需求自行抉择。这不仅给开发者带来了麻烦,也给用户带来了困扰。他们不仅需要理解不同连接点的特征,还需要不胜其烦地进行选择和切换,这就为应用连接网络带来了极大的复杂度,使得联网操作变得别扭而晦涩。

在Android中,连接点选择的工作被封装在了系统底层,网络管理服务会从可用连接点中选择一个“最好的”的作为当前连接点,整个系统的所有应用都通过它连接网络,而不再需要各个应用分别抉择,这使得联网变得自然简单。

Android对最好连接点的抉择是一个静态策略,它会根据不同联网方式的先验知识做出判断,而不是根据当前的实际联网速度进行选择。在该策略下,Android会优先选择通过WiFi连接网络,如果所有WiFi连接点均处于不可用状态,就会依次考虑3G网络、EDGE网络、GPRS网络,等等。此外,Android系统会时刻关注连接点可用性的变化,一旦当前连接点变成了不可用状态,它会立刻进行切换,使用新的最优可用连接点进行联网。与之类似,如果系统中出现了高优先级的可用连接点,Android也会将当前连接点切换为它。

在应用中,Android可以通过android.net.ConnectivityManager对象来查看和管理当前的联网方式。比如,使用ConnectivityManager.getActiveNetworkInfo函数可以获得当前联网方式的信息,应用可以根据这些信息做出不同的处理:


ConnectivityManager manager=(ConnectivityManager)

getSystemService(CONNECTIVITY_SERVICE);

NetworkInfo info=manager.getActiveNetworkInfo();

If(info.getType()==ConnectivityManager.TYPE_WIFI){

…//在WiFi连接时,进行特殊的处理,比如下载大文件,等等

}else{

…//在其他网络连接时,做不同的处理

}


从Android的设计来看,开发者本应无需了解和设置连接点的信息,但如果应用需要支持“中国特色”的cmwap等连接点,就需要获取连接点的代理信息进行配置。这是因为cmwap等连接点,需要通过特定的代理服务连接网络,而Android并不会在联网时添加这些代理信息,这就要求开发者在联网时自行掌控添加。

与通信网络相关的连接点信息存储在连接点数据源中,通过查询该数据源可以获得连接点相关的代理信息,示例如下:


HttpClient client=new DefaultHttpClient();

//首先需要判断当前联网方式是否通过通信网络

ConnectivityManager manager=(ConnectivityManager)

getSystemService(CONNECTIVITY_SERVICE);

NetworkInfo netInfo=manager.getActiveNetworkInfo();

if(netInfo==null||

netInfo.getType()!=ConnectivityManager.TYPE_WIFI){

//从数据源组件中查询当前的连接点信息

apnCursor=getContentResolver().query(

Uri.parse("content://telephony/carriers/preferapn"),

new String[]{"apn","proxy","port"},

null, null, null);

final String apnProxy=apnCursor.getString(1);

final String apnPort=apnCursor.getString(2);

apnCursor.close();

//为HttpClient设置代理

if(!TextUtils.isEmpty(apnProxy)){

int port=80;

if(!TextUtils.isEmpty(apnPort)){

port=Integer.parseInt(apnPort);

}

HttpHost proxy=new HttpHost(host, port);

client.getParams().setParameter(

ConnRouteParams.DEFAULT_PROXY, proxy);

}

}