执行网络操作
这一部分阐述了如何来进行最基本的网络连接任务,管理网络连接(包含网络状态的改变),还有让用户来管理一个应用网络的用法,还有描述了如何来解析和运用XML数据
经过学习了这些课程后,你能够基本的在一个应用中有效的从网络上下载和解析数据,并且使用最少的网络资源
通过本章你将会学到
连接到网络
怎么样去连接一个网络,选择合适的HTTP的客户端,在UI祝线程外执行一个网络操作
管理网络的使用
怎么样去检查网络连接状态,创建一个前台界面去管理网络的使用,怎么去应对网络状态改变
解析 XML 数据
怎么样去解析和使用XML数据
网络操作最佳实践
取得device的网络连接状态
// Checks the network connection and sets the wifiConnected and mobileConnected
// variables accordingly.
private void updateConnectedFlags() {
//网络管理服务
ConnectivityManager connMgr =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE );
NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
if (activeInfo != null && activeInfo.isConnected()) {
//wifi 连接状态
wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI ;
//mobile连接状态
mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE ;
} else {
wifiConnected = false ;
mobileConnected = false ;
}
}
在UI主线程外运用AsyncTask类异步的执行网络连接操作
// Implementation of AsyncTask used to download XML feed from stackoverflow.com.
private class DownloadXmlTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground( String... urls) {
try {
return loadXmlFromNetwork(urls[0]);
} catch (IOException e) {
return getResources().getString(R.string.connection_error);
} catch (XmlPullParserException e) {
return getResources().getString(R.string.xml_error);
}
}
@Override
protected void onPostExecute(String result) {
setContentView(R.layout. activity_main);
// Displays the HTML string in the UI via a WebView
WebView myWebView = (WebView) findViewById(R.id. webview);
myWebView.loadData(result, "text/html", null );
}
}
执行网络连接
// Given a string representation of a URL, sets up a connection and gets
// an input stream.
private InputStream downloadUrl(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url. openConnection();
//设置读取网络流的超时时间
conn.setReadTimeout(10000 /* milliseconds */);
//设置网络连接超时时间
conn.setConnectTimeout(15000 /* milliseconds */);
//设置为GET请求
conn. setRequestMethod("GET");
//设置允许读取网络输入流
conn.setDoInput( true);
// Starts the query
conn. connect();
InputStream stream = conn. getInputStream();
return stream;
}
在Android操作系统中,每次网络状态有变化时都会发送一个广播,我们只要注册了该广播的接收器,就可以得知网络状态的变化了
// Register BroadcastReceiver to track connection changes.
// 动态注册广播接收器去接收网络状态改变的广播
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION );
receiver = new NetworkReceiver();
this.registerReceiver( receiver, filter);
/**
*
* This BroadcastReceiver intercepts the android.net.ConnectivityManager.CONNECTIVITY_ACTION,
* which indicates a connection change. It checks whether the type is TYPE_WIFI.
* If it is, it checks whether Wi- Fi is connected and sets the wifiConnected flag in the
* main activity accordingly.
* 网络状态改变时,进行一些处理
*/
public class NetworkReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connMgr =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE );
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
// Checks the user prefs and the network connection. Based on the result, decides
// whether
// to refresh the display or keep the current display.
// If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection.
if (WIFI .equals(sPref) && networkInfo != null
&& networkInfo.getType() == ConnectivityManager. TYPE_WIFI) {
// If device has its Wi-Fi connection, sets refreshDisplay
// to true. This causes the display to be refreshed when the user
// returns to the app.
refreshDisplay = true ;
Toast. makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show();
// If the setting is ANY network and there is a network connection
// (which by process of elimination would be mobile), sets refreshDisplay to true.
} else if (ANY.equals(sPref) && networkInfo != null) {
refreshDisplay = true ;
// Otherwise, the app can't download content--either because there is no network
// connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there
// is no Wi -Fi connection.
// Sets refreshDisplay to false.
} else {
refreshDisplay = false ;
Toast. makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
}
}
}
Android SDK 自带的解析器PULL解析xml时最佳实践点
//设置不使用namespace特性,节省资源,加快解析速度
parser.setFeature(XmlPullParser. FEATURE_PROCESS_NAMESPACES, false );
//测试一下是否是标签的起始,支持任何 namespace,标签的名为feed.有效的减少一些无效的解析操作
parser.require(XmlPullParser. START_TAG, ns , "feed" );
// Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
// if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
// finds the matching END_TAG (as indicated by the value of "depth" being 0).
// 跳过一些对我们无用的标签不进行解析,不需要每次都去判断当前标签是否是我们需要的标签,加快解析速度
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
总结
在Android中去执行一个网络任务,一般要在UI主线程之外的线程中去执行以免阻塞UI主线程,监听到网络状态的变化,进而做一些操作,是很有必要的!有助于我们的应用提供更好的用户体验。xml数据的解析也需要更好的进行优化,以更快的速度把数据展现在用户面前,这些都是很好的实践。