Android联网功能
Android网络包
1,java.net 提供与联网有关的类, 包括流和数据包(datagram)sockets,Internet协议和常见HTTP处理。该包是一个多功能网络资源。
2,java.io 虽然没有提供显示的联网功能,但是仍然非常重要。该包中的类由其他Java包中提供的socket和连接使用。它们还拥有与本地文件(在与网络进行交互时会经常出现)的交互
3,java.nio 包含表示特定数据类型的缓存区的类。适合用于连个基于Java语言的端点之间的通信。
4,org.apache.* 表示许多为HTTP通信提供精确控制和功能的包。可以将Apache视为流行的开源Web服务器。
5,android.net 除核心java.net.*类以外,包含额外的网络访问socket。该包包括URI类,后者频繁用于Android应用程序开发,而不仅仅是传统的联网方面。
6,android.net.http 包含处理SSL证书的类。
关于java.net包中的应用,socket一般很少用到,URLConnection的应用可以参见:http://blog.csdn.net/pipisky2006/article/details/6321411
android.net包中的常用到的类由ConnectivityManager,NetWorkInfo,Proxy,Uri,WifiManager等,
其中ConnectivityManager可以获取网络状态,为了省电,联网之前先判断网络状态,无网络直接进行提示。
/**
* Returns whether the network is available网络是否可用
*/
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivity =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
Log.w(Constants.TAG, "couldn't get connectivity manager");
} else {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
if (Constants.LOGVV) {
Log.v(Constants.TAG, "network is available");
}
return true;
}
}
}
}
if (Constants.LOGVV) {
Log.v(Constants.TAG, "network is not available");
}
return false;
}
个人认为更为系统的方法应该是在程序启动的时候读取一次网络状态,同时在Service或者Application中注册个Receiver,监听Action,ConnectivityManager.CONNECTIVITY_ACTION,这样就不用每一次网络请求的时候都去读取一次getNetworkInfo了。
// 获取Mobile网络下的cmwap、cmnet
public static int handleNetWorkState(Context context)
{
int type = NETWORK_TYPE_NULL;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null)
{
if (info.getType() == ConnectivityManager.TYPE_WIFI)
{
type = NETWORK_TYPE_WIFI;
}
}
if (type != NETWORK_TYPE_WIFI)
{
if (info !=null && info.getType()==ConnectivityManager.TYPE_MOBILE)
{
Cursor cursor = null;
try
{
cursor = context.getContentResolver().query(PREFERRED_APN_URI, new String[] { "_id", "apn", "type" },
null, null, null);
cursor.moveToFirst();
int counts = cursor.getCount();
if (counts != 0)
{
if (!cursor.isAfterLast())
{
String apn = cursor.getString(1);
if (apn.equalsIgnoreCase("cmnet")
|| apn.equalsIgnoreCase("uninet")
|| apn.equalsIgnoreCase("ctnet"))
{
type = NETWORK_TYPE_CMNET;
} else if (apn.equalsIgnoreCase("cmwap") || apn.equalsIgnoreCase("3gwap")
|| apn.equalsIgnoreCase("uniwap") || apn.toLowerCase().indexOf("wap") != -1)
{
type = NETWORK_TYPE_CMWAP;
}else
{
type = NETWORK_TYPE_CMNET;
}
}
} else
{
type = NETWORK_TYPE_CMNET;
}
} catch (Exception e)
{
e.printStackTrace();
} finally
{
try
{
cursor.close();
} catch (Exception e)
{
}
}
}
}
if (type != mNetState)
{
mNetState = type;
}
return type;
}
String proxyHost = android.net.Proxy.getDefaultHost();
// 代理模式
if (proxyHost != null && useProxy && mNetstate == NETWORK_TYPE_CMWAP) {
java.net.Proxy p = new java.net.Proxy(java.net.Proxy.Type.HTTP, new InetSocketAddress(android.net.Proxy.getDefaultHost(),android.net.Proxy.getDefaultPort()));
httpURLConn = (HttpURLConnection) new URL(mReqUrl).openConnection(p);
}
else {// 直连模式
httpURLConn = (HttpURLConnection) new URL(mReqUrl).openConnection();
}
String proxyHost = android.net.Proxy.getDefaultHost(); if (proxyHost != null && mNetstate == NETWORK_TYPE_CMWAP && useProxy){ HttpHost proxy = new HttpHost(android.net.Proxy.getDefaultHost(), android.net.Proxy.getDefaultPort(),"http"); client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); // params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); }
在cmwap并且android默认有代理并且useProxy为true的情况下使用代理,有些情况下不一般,可以再网络连接错误的情况下再设置useProxy为false重连一次。另外还有apn查询的方法,见http://7dot9.com/2010/07/android%E4%B8%8A%E5%A6%82%E4%BD%95%E6%AD%A3%E7%A1%AE%E5%AE%9E%E7%8E%B0%E7%A8%8B%E5%BA%8F%E7%9A%84%E8%81%94%E7%BD%91/
接下来,看看org.apache.commons.HttpClient,这个项目就是专门设计来简化HTTP客户端与服务器进行各种通讯编程。
使用 HttpClient 需要以下 6 个步骤:
1. 创建 HttpClient 的实例
2. 创建某种连接方法的实例,在这里是 GetMethod。在 GetMethod 的构造函数中传入待连接的地址
3. 调用第一步中创建好的实例的 execute 方法来执行第二步中创建好的 method 实例
4. 读 response
5. 释放连接。无论执行方法是否成功,都必须释放连接
6. 对得到后的内容进行处理
先看HttpParams,HTTP 协议和框架参数的集合。
// 创建 HttpParams 以用来设置 HTTP 参数
HttpParams params = new BasicHttpParams();
//HttpProtocolParams设置一些和协议相关的
HttpProtocolParams.setUserAgent(params, userAgent);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf-8");
HttpProtocolParams.setHttpElementCharset(params, "utf-8");
HttpProtocolParams.setUseExpectContinue(params, true);
// HttpConnectionParams设置连接超时和 Socket 超时,以及 Socket 缓存大小
HttpConnectionParams.setConnectionTimeout(params, 20 * 1000 );
HttpConnectionParams.setSoTimeout(params, 20 * 1000 );
HttpConnectionParams.setSocketBufferSize(params, 8192 );
// HttpClientParams 设置重定向,缺省为 true 和Cookie之类的
HttpClientParams.setRedirecting(params, true );
最简单的也可以之间进行参数设置
params.setParameter("Connection", "Keep-Alive");
params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
还有可以交互的数据就是Http协议头,Header类,参加http://blog.csdn.net/pipisky2006/article/details/6085532,头信息都可以设置
例如
ArrayList<Header> heads = new ArrayList<Header>();
heads.add(new BasicHeader("Accept-Encoding", "gzip"));
heads.add(new BasicHeader("Connection", "Keep-Alive"));
heads.add(new BasicHeader("Range", range));
headers = heads.toArray();
HttpPost post = new HttpPost(u.toURI());
post.setHeaders(headers);
import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.params. HttpConnectionParams; import org.apache.http.client.params. HttpClientParams; try { // 创建 HttpParams 以用来设置 HTTP 参数(这一部分不是必需的) HttpParams params = new BasicHttpParams(); // 设置连接超时和 Socket 超时,以及 Socket 缓存大小 HttpConnectionParams.setConnectionTimeout(params, 20 * 1000 ); HttpConnectionParams.setSoTimeout(params, 20 * 1000 ); HttpConnectionParams.setSocketBufferSize(params, 8192 ); // 设置重定向,缺省为 true HttpClientParams.setRedirecting(params, true ); // 设置 user agent HttpProtocolParams.setUserAgent(params, userAgent); // 创建一个 HttpClient 实例 // 注意 HttpClient httpClient = new HttpClient(); 是 Commons HttpClient // 中的用法,在 Android 1.5 中我们需要使用 Apache 的缺省实现 DefaultHttpClient HttpClient httpClient = new DefaultHttpClient(); // 创建 HttpGet 方法,该方法会自动处理 URL 地址的重定向 HttpGet httpGet = new HttpGet ( "http://www.test_test.com/" ); httpGet.setParams(params); HttpResponse response = client.execute(httpGet); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { // 错误处理,例如可以在该请求正常结束前将其中断 httpGet.abort(); } // 读取更多信息 Header[] headers = response.getHeaders(); HttpEntity entity = response.getEntity(); Header header = response.getFirstHeader( "Content-Type" ); } catch (Exception ee) { // } finally { // 释放连接 client.getConnectionManager().shutdown(); }
如果是post,还要多个请求正文的Entity
如果是键值对,可以使用 List <NameValuePair> nvps = new ArrayList <NameValuePair>();
// BasicNameValuePair("name", "value"), name是post方法里的属性, value是传入的参数值
nvps.add(new BasicNameValuePair("name1", "value1"));
httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)); //将参数传入post方法中
也可以是StringEntity,FileEntity等
HttpEntity enti = new StringEntity(new String(data), "utf-8");
httppost.setEntity(enti);
在响应返回后,响应正文中也可以读到entity,在数据处理完成后entity.consumeContent();
HttpEntity entity = response.getEntity();
另外要注意的编码问题,
String encode = null;
if (entity.getContentEncoding() != null){
encode = entity.getContentEncoding().getValue();
}
最后看看重定向
// 判断页面返回状态判断是否进行转向抓取新链接
int statusCode = response.getStatusLine().getStatusCode();
if ((statusCode == HttpStatus.SC_MOVED_PERMANENTLY) ||
(statusCode == HttpStatus.SC_MOVED_TEMPORARILY) ) {
Header head = response.getFirstHeader("Location");
if (head != null){
String reUrl = head.getValue();
//这里可以拿着reUrl再做一次请求了
}
}
参考:http://www.ibm.com/developerworks/cn/opensource/os-httpclient/
http://blog.csdn.net/dww410/article/details/6608695