本篇我们会介绍连接到网络中涉及的基本任务,监测的网络连接(包括连接更改),并给予用户控制应用程序的网络使用情况。还介绍了如何解析和使用XML数据。
这个类包含一个示例应用程序来说明如何执行常见的网络操作。您可以下载示例(在右边),并用它作为自己的应用程序源代码的可重用代码。本章的重点有三:
1.连接到网络
2.管理网络的使用
3.解析XML数据
一、连接到网络
在mainfest中声明权限,代码如下:
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
选择http客户端
大多数联网的Android应用程序使用HTTP来发送和接收数据。Android包括两个HTTP客户:HttpURLConnection HttpClient和Apache。都支持HTTPS,流媒体上传和下载,可配置的超时,IPv6,和连接池。我们建议使用HttpURLConnection目标应用程序。
检查网络连接
在你的应用程序尝试连接到网络,它应该检查是否一个网络连接可用使用getActiveNetworkInfo()和一个()。记住,这个装置可能范围的一个网络,或用户可能已经禁用wi - fi和移动数据访问。
- public void myClickHandler(View view) {
- ...
- ConnectivityManager connMgr = (ConnectivityManager)
- getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
- if (networkInfo != null && networkInfo.isConnected()) {
- // fetch data
- } else {
- // display error
- }
- ...
- }
在单独线程中执行网络操作
网络操作可以包括不可预测的延迟。为了防止这种导致一个糟糕的用户体验,总是执行网络操作在一个单独的线程。
- public class HttpExampleActivity extends Activity {
- private static final String DEBUG_TAG = "HttpExample";
- private EditText urlText;
- private TextView textView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- urlText = (EditText) findViewById(R.id.myUrl);
- textView = (TextView) findViewById(R.id.myText);
- }
- // When user clicks button, calls AsyncTask.
- // Before attempting to fetch the URL, makes sure that there is a network connection.
- public void myClickHandler(View view) {
- // Gets the URL from the UI's text field.
- String stringUrl = urlText.getText().toString();
- ConnectivityManager connMgr = (ConnectivityManager)
- getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
- if (networkInfo != null && networkInfo.isConnected()) {
- new DownloadWebpageText().execute(stringUrl);
- } else {
- textView.setText("No network connection available.");
- }
- }
- // Uses AsyncTask to create a task away from the main UI thread. This task takes a
- // URL string and uses it to create an HttpUrlConnection. Once the connection
- // has been established, the AsyncTask downloads the contents of the webpage as
- // an InputStream. Finally, the InputStream is converted into a string, which is
- // displayed in the UI by the AsyncTask's onPostExecute method.
- private class DownloadWebpageText extends AsyncTask {
- @Override
- protected String doInBackground(String... urls) {
- // params comes from the execute() call: params[0] is the url.
- try {
- return downloadUrl(urls[0]);
- } catch (IOException e) {
- return "Unable to retrieve web page. URL may be invalid.";
- }
- }
- // onPostExecute displays the results of the AsyncTask.
- @Override
- protected void onPostExecute(String result) {
- textView.setText(result);
- }
- }
- ...
- }
连接和下载数据
在你的线程执行您的网络交易,你可以使用HttpURLConnection来执行一个GET和下载数据。在您调用connect(),你可以得到一个InputStream的数据通过调用getInputStream()。
- // Given a URL, establishes an HttpUrlConnection and retrieves
- // the web page content as a InputStream, which it returns as
- // a string.
- private String downloadUrl(String myurl) throws IOException {
- InputStream is = null;
- // Only display the first 500 characters of the retrieved
- // web page content.
- int len = 500;
- try {
- URL url = new URL(myurl);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setReadTimeout(10000 /* milliseconds */);
- conn.setConnectTimeout(15000 /* milliseconds */);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- // Starts the query
- conn.connect();
- int response = conn.getResponseCode();
- Log.d(DEBUG_TAG, "The response is: " + response);
- is = conn.getInputStream();
- // Convert the InputStream into a string
- String contentAsString = readIt(is, len);
- return contentAsString;
- // Makes sure that the InputStream is closed after the app is
- // finished using it.
- } finally {
- if (is != null) {
- is.close();
- }
- }
- }
getResponseCode()返回连接的状态码。这是一种有用的方式获得一些额外的信息的连接。一个200的状态代码表示成功。
转换InputStream到String
- // Reads an InputStream and converts it to a String.
- public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
- Reader reader = null;
- reader = new InputStreamReader(stream, "UTF-8");
- char[] buffer = new char[len];
- reader.read(buffer);
- return new String(buffer);
- }
二、管理网络
检查设备的网络连接
一个设备可以有各种类型的网络连接。这节课的重点是使用wi - fi或手机或网络连接,这个代码片段测试网络连接wi - fi和移动。它确定这些网络接口是可用的或连接的(即网络连接是否存在,如果可以建立套接字和传递数据)
- private static final String DEBUG_TAG = "NetworkStatusExample";
- ...
- ConnectivityManager connMgr = (ConnectivityManager)
- getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- boolean isWifiConn = networkInfo.isConnected();
- networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- boolean isMobileConn = networkInfo.isConnected();
- Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
- Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);
管理网络的使用
您可以实现一个首选项活动,让用户明确控制应用程序的使用网络资源。例如: 1.你可能允许用户上传的视频只有当设备被连接到wi - fi网络。2.你可能会同步(或没有)根据特定标准如网络可用性、时间间隔,等等。
编写一个应用程序,支持网络访问和管理网络的使用,你的清单必须有正确的权限和意图过滤器。
在样例应用程序中,这个规定了SettingsActivity,将显示一个UI让用户知道何时可以进行下载操作。
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.networkusage"
- ...>
- <uses-sdk android:minSdkVersion="4"
- android:targetSdkVersion="14" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <application
- ...>
- ...
- <activity android:label="SettingsActivity" android:name=".SettingsActivity">
- <intent-filter>
- <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
- public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // Loads the XML preferences file
- addPreferencesFromResource(R.xml.preferences);
- }
- @Override
- protected void onResume() {
- super.onResume();
- // Registers a listener whenever a key changes
- getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
- }
- @Override
- protected void onPause() {
- super.onPause();
- // Unregisters the listener set in onResume().
- // It's best practice to unregister listeners when your app isn't using them to cut down on
- // unnecessary system overhead. You do this in onPause().
- getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
- }
- // When the user changes the preferences selection,
- // onSharedPreferenceChanged() restarts the main activity as a new
- // task. Sets the the refreshDisplay flag to "true" to indicate that
- // the main activity should update its display.
- // The main activity queries the PreferenceManager to get the latest settings.
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- // Sets refreshDisplay to true so that when the user returns to the main
- // activity, the display refreshes to reflect the new settings.
- NetworkActivity.refreshDisplay = true;
- }
- }
响应网络变动
如果有一个匹配发生在设置和设备的网络连接(例如,如果设置为“wi - fi”和设备有一个wi - fi连接)之间,应用程序下载提继续并刷新显示
- public class NetworkActivity extends Activity {
- public static final String WIFI = "Wi-Fi";
- public static final String ANY = "Any";
- private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
- // Whether there is a Wi-Fi connection.
- private static boolean wifiConnected = false;
- // Whether there is a mobile connection.
- private static boolean mobileConnected = false;
- // Whether the display should be refreshed.
- public static boolean refreshDisplay = true;
- // The user's current network preference setting.
- public static String sPref = null;
- // The BroadcastReceiver that tracks network connectivity changes.
- private NetworkReceiver receiver = new NetworkReceiver();
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // Registers BroadcastReceiver to track network connection changes.
- IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
- receiver = new NetworkReceiver();
- this.registerReceiver(receiver, filter);
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- // Unregisters BroadcastReceiver when app is destroyed.
- if (receiver != null) {
- this.unregisterReceiver(receiver);
- }
- }
- // Refreshes the display if the network connection and the
- // pref settings allow it.
- @Override
- public void onStart () {
- super.onStart();
- // Gets the user's network preference settings
- SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- // Retrieves a string value for the preferences. The second parameter
- // is the default value to use if a preference value is not found.
- sPref = sharedPrefs.getString("listPref", "Wi-Fi");
- updateConnectedFlags();
- if(refreshDisplay){
- loadPage();
- }
- }
- // Checks the network connection and sets the wifiConnected and mobileConnected
- // variables accordingly.
- public void updateConnectedFlags() {
- ConnectivityManager connMgr = (ConnectivityManager)
- getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
- if (activeInfo != null && activeInfo.isConnected()) {
- wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
- mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
- } else {
- wifiConnected = false;
- mobileConnected = false;
- }
- }
- // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
- public void loadPage() {
- if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
- || ((sPref.equals(WIFI)) && (wifiConnected))) {
- // AsyncTask subclass
- new DownloadXmlTask().execute(URL);
- } else {
- showErrorPage();
- }
- }
- ...
- }
检测网络连接变化
- public class NetworkReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- ConnectivityManager conn = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = conn.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();
- }
- }
三、解析xml
上传和解析XML数据是很常见的任务,网络连接应用程序。这一课解释了如何解析XML文档并使用他们的数据
选择转换器
我们建议XmlPullParser,这是一种高效且可维护的方式来解析XML在Android里。
分析需求
- <?xml version="1.0" encoding="utf-8"?>
- <feed xmlns="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" ...">
- <title type="text">newest questions tagged android - Stack Overflow</title>
- ...
- <entry>
- ...
- </entry>
- <entry>
- <id>http://stackoverflow.com/q/9439999</id>
- <re:rank scheme="http://stackoverflow.com">0</re:rank>
- <title type="text">Where is my data file?</title>
- <category scheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags" term="android"/>
- <category scheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags" term="file"/>
- <author>
- <name>cliff2310</name>
- <uri>http://stackoverflow.com/users/1128925</uri>
- </author>
- <link rel="alternate" href="http://stackoverflow.com/questions/9439999/where-is-my-data-file" />
- <published>2012-02-25T00:30:54Z</published>
- <updated>2012-02-25T00:30:54Z</updated>
- <summary type="html">
- <p>I have an Application that requires a data file...</p>
- </summary>
- </entry>
- <entry>
- ...
- </entry>
- ...
- </feed>
实例化转化器
- public class StackOverflowXmlParser {
- // We don't use namespaces
- private static final String ns = null;
- public List parse(InputStream in) throws XmlPullParserException, IOException {
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
- parser.setInput(in, null);
- parser.nextTag();
- return readFeed(parser);
- } finally {
- in.close();
- }
- }
- ...
- }
- 读取xml
- private List readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
- List entries = new ArrayList();
- parser.require(XmlPullParser.START_TAG, ns, "feed");
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- String name = parser.getName();
- // Starts by looking for the entry tag
- if (name.equals("entry")) {
- entries.add(readEntry(parser));
- } else {
- skip(parser);
- }
- }
- return entries;
- }
下面这个代码片段展示了如何解析器解析条目、标题、链接和总结:
- public static class Entry {
- public final String title;
- public final String link;
- public final String summary;
- private Entry(String title, String summary, String link) {
- this.title = title;
- this.summary = summary;
- this.link = link;
- }
- }
- // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them off
- // to their respective "read" methods for processing. Otherwise, skips the tag.
- private Entry readEntry(XmlPullParser parser) throws XmlPullParserException, IOException {
- parser.require(XmlPullParser.START_TAG, ns, "entry");
- String title = null;
- String summary = null;
- String link = null;
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- String name = parser.getName();
- if (name.equals("title")) {
- title = readTitle(parser);
- } else if (name.equals("summary")) {
- summary = readSummary(parser);
- } else if (name.equals("link")) {
- link = readLink(parser);
- } else {
- skip(parser);
- }
- }
- return new Entry(title, summary, link);
- }
- // Processes title tags in the feed.
- private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
- parser.require(XmlPullParser.START_TAG, ns, "title");
- String title = readText(parser);
- parser.require(XmlPullParser.END_TAG, ns, "title");
- return title;
- }
- // Processes link tags in the feed.
- private String readLink(XmlPullParser parser) throws IOException, XmlPullParserException {
- String link = "";
- parser.require(XmlPullParser.START_TAG, ns, "link");
- String tag = parser.getName();
- String relType = parser.getAttributeValue(null, "rel");
- if (tag.equals("link")) {
- if (relType.equals("alternate")){
- link = parser.getAttributeValue(null, "href");
- parser.nextTag();
- }
- }
- parser.require(XmlPullParser.END_TAG, ns, "link");
- return link;
- }
- // Processes summary tags in the feed.
- private String readSummary(XmlPullParser parser) throws IOException, XmlPullParserException {
- parser.require(XmlPullParser.START_TAG, ns, "summary");
- String summary = readText(parser);
- parser.require(XmlPullParser.END_TAG, ns, "summary");
- return summary;
- }
- // For the tags title and summary, extracts their text values.
- private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
- String result = "";
- if (parser.next() == XmlPullParser.TEXT) {
- result = parser.getText();
- parser.nextTag();
- }
- return result;
- }
- ...
- }
跳过无用的标签
- 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;
- }
- }
- }
使用xml数据
- public class NetworkActivity extends Activity {
- public static final String WIFI = "Wi-Fi";
- public static final String ANY = "Any";
- private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
- // Whether there is a Wi-Fi connection.
- private static boolean wifiConnected = false;
- // Whether there is a mobile connection.
- private static boolean mobileConnected = false;
- // Whether the display should be refreshed.
- public static boolean refreshDisplay = true;
- public static String sPref = null;
- ...
- // Uses AsyncTask to download the XML feed from stackoverflow.com.
- public void loadPage() {
- if((sPref.equals(ANY)) && (wifiConnected || mobileConnected)) {
- new DownloadXmlTask().execute(URL);
- }
- else if ((sPref.equals(WIFI)) && (wifiConnected)) {
- new DownloadXmlTask().execute(URL);
- } else {
- // show error
- }
- }
动态下载xml
- // 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.main);
- // Displays the HTML string in the UI via a WebView
- WebView myWebView = (WebView) findViewById(R.id.webview);
- myWebView.loadData(result, "text/html", null);
- }
- }
加载xml
- // Uploads XML from stackoverflow.com, parses it, and combines it with
- // HTML markup. Returns HTML string.
- private String loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException {
- InputStream stream = null;
- // Instantiate the parser
- StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser();
- List<Entry> entries = null;
- String title = null;
- String url = null;
- String summary = null;
- Calendar rightNow = Calendar.getInstance();
- DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa");
- // Checks whether the user set the preference to include summary text
- SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- boolean pref = sharedPrefs.getBoolean("summaryPref", false);
- StringBuilder htmlString = new StringBuilder();
- htmlString.append("<h3>" + getResources().getString(R.string.page_title) + "</h3>");
- htmlString.append("<em>" + getResources().getString(R.string.updated) + " " +
- formatter.format(rightNow.getTime()) + "</em>");
- try {
- stream = downloadUrl(urlString);
- entries = stackOverflowXmlParser.parse(stream);
- // Makes sure that the InputStream is closed after the app is
- // finished using it.
- } finally {
- if (stream != null) {
- stream.close();
- }
- }
- // StackOverflowXmlParser returns a List (called "entries") of Entry objects.
- // Each Entry object represents a single post in the XML feed.
- // This section processes the entries list to combine each entry with HTML markup.
- // Each entry is displayed in the UI as a link that optionally includes
- // a text summary.
- for (Entry entry : entries) {
- htmlString.append("<p><a href='");
- htmlString.append(entry.link);
- htmlString.append("'>" + entry.title + "</a></p>");
- // If the user set the preference to include summary text,
- // adds it to the display.
- if (pref) {
- htmlString.append(entry.summary);
- }
- }
- return htmlString.toString();
- }
- // 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 */);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- // Starts the query
- conn.connect();
- InputStream stream = conn.getInputStream();
- }
上面的片段代码为了帮助大家理解,这里还是老习惯,贴上项目的源代码,本来是有项目截图,运行效果图之类的图的,只是这篇文章太长了,再弄图片,就更占篇幅了,所以就只贴源码了,大家可以自己的运行起来看看,希望能从整体的架构和具体的代码细节上帮助到大家。
本篇我们会介绍连接到网络中涉及的基本任务,监测的网络连接(包括连接更改),并给予用户控制应用程序的网络使用情况。还介绍了如何解析和使用XML数据。这个类包含一个示例应用程序来说明如何执行常见的网络操作。您可以下载示例(在右边),并用它作为自己的应用程序源代码的可重用代码。本章的重点有三:
1.连接到网络
2.管理网络的使用
3.解析XML数据
一、连接到网络
在mainfest中声明权限,代码如下:
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
选择http客户端
大多数联网的Android应用程序使用HTTP来发送和接收数据。Android包括两个HTTP客户:HttpURLConnection HttpClient和Apache。都支持HTTPS,流媒体上传和下载,可配置的超时,IPv6,和连接池。我们建议使用HttpURLConnection目标应用程序。
检查网络连接
在你的应用程序尝试连接到网络,它应该检查是否一个网络连接可用使用getActiveNetworkInfo()和一个()。记住,这个装置可能范围的一个网络,或用户可能已经禁用wi - fi和移动数据访问。
- public void myClickHandler(View view) {
- ...
- ConnectivityManager connMgr = (ConnectivityManager)
- getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
- if (networkInfo != null && networkInfo.isConnected()) {
- // fetch data
- } else {
- // display error
- }
- ...
- }
在单独线程中执行网络操作
网络操作可以包括不可预测的延迟。为了防止这种导致一个糟糕的用户体验,总是执行网络操作在一个单独的线程。
- public class HttpExampleActivity extends Activity {
- private static final String DEBUG_TAG = "HttpExample";
- private EditText urlText;
- private TextView textView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- urlText = (EditText) findViewById(R.id.myUrl);
- textView = (TextView) findViewById(R.id.myText);
- }
- // When user clicks button, calls AsyncTask.
- // Before attempting to fetch the URL, makes sure that there is a network connection.
- public void myClickHandler(View view) {
- // Gets the URL from the UI's text field.
- String stringUrl = urlText.getText().toString();
- ConnectivityManager connMgr = (ConnectivityManager)
- getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
- if (networkInfo != null && networkInfo.isConnected()) {
- new DownloadWebpageText().execute(stringUrl);
- } else {
- textView.setText("No network connection available.");
- }
- }
- // Uses AsyncTask to create a task away from the main UI thread. This task takes a
- // URL string and uses it to create an HttpUrlConnection. Once the connection
- // has been established, the AsyncTask downloads the contents of the webpage as
- // an InputStream. Finally, the InputStream is converted into a string, which is
- // displayed in the UI by the AsyncTask's onPostExecute method.
- private class DownloadWebpageText extends AsyncTask {
- @Override
- protected String doInBackground(String... urls) {
- // params comes from the execute() call: params[0] is the url.
- try {
- return downloadUrl(urls[0]);
- } catch (IOException e) {
- return "Unable to retrieve web page. URL may be invalid.";
- }
- }
- // onPostExecute displays the results of the AsyncTask.
- @Override
- protected void onPostExecute(String result) {
- textView.setText(result);
- }
- }
- ...
- }
连接和下载数据
在你的线程执行您的网络交易,你可以使用HttpURLConnection来执行一个GET和下载数据。在您调用connect(),你可以得到一个InputStream的数据通过调用getInputStream()。
- // Given a URL, establishes an HttpUrlConnection and retrieves
- // the web page content as a InputStream, which it returns as
- // a string.
- private String downloadUrl(String myurl) throws IOException {
- InputStream is = null;
- // Only display the first 500 characters of the retrieved
- // web page content.
- int len = 500;
- try {
- URL url = new URL(myurl);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setReadTimeout(10000 /* milliseconds */);
- conn.setConnectTimeout(15000 /* milliseconds */);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- // Starts the query
- conn.connect();
- int response = conn.getResponseCode();
- Log.d(DEBUG_TAG, "The response is: " + response);
- is = conn.getInputStream();
- // Convert the InputStream into a string
- String contentAsString = readIt(is, len);
- return contentAsString;
- // Makes sure that the InputStream is closed after the app is
- // finished using it.
- } finally {
- if (is != null) {
- is.close();
- }
- }
- }
getResponseCode()返回连接的状态码。这是一种有用的方式获得一些额外的信息的连接。一个200的状态代码表示成功。
转换InputStream到String
- // Reads an InputStream and converts it to a String.
- public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
- Reader reader = null;
- reader = new InputStreamReader(stream, "UTF-8");
- char[] buffer = new char[len];
- reader.read(buffer);
- return new String(buffer);
- }
二、管理网络
检查设备的网络连接
一个设备可以有各种类型的网络连接。这节课的重点是使用wi - fi或手机或网络连接,这个代码片段测试网络连接wi - fi和移动。它确定这些网络接口是可用的或连接的(即网络连接是否存在,如果可以建立套接字和传递数据)
- private static final String DEBUG_TAG = "NetworkStatusExample";
- ...
- ConnectivityManager connMgr = (ConnectivityManager)
- getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- boolean isWifiConn = networkInfo.isConnected();
- networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
- boolean isMobileConn = networkInfo.isConnected();
- Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
- Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);
管理网络的使用
您可以实现一个首选项活动,让用户明确控制应用程序的使用网络资源。例如: 1.你可能允许用户上传的视频只有当设备被连接到wi - fi网络。2.你可能会同步(或没有)根据特定标准如网络可用性、时间间隔,等等。
编写一个应用程序,支持网络访问和管理网络的使用,你的清单必须有正确的权限和意图过滤器。
在样例应用程序中,这个规定了SettingsActivity,将显示一个UI让用户知道何时可以进行下载操作。
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.networkusage"
- ...>
- <uses-sdk android:minSdkVersion="4"
- android:targetSdkVersion="14" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <application
- ...>
- ...
- <activity android:label="SettingsActivity" android:name=".SettingsActivity">
- <intent-filter>
- <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
- public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // Loads the XML preferences file
- addPreferencesFromResource(R.xml.preferences);
- }
- @Override
- protected void onResume() {
- super.onResume();
- // Registers a listener whenever a key changes
- getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
- }
- @Override
- protected void onPause() {
- super.onPause();
- // Unregisters the listener set in onResume().
- // It's best practice to unregister listeners when your app isn't using them to cut down on
- // unnecessary system overhead. You do this in onPause().
- getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
- }
- // When the user changes the preferences selection,
- // onSharedPreferenceChanged() restarts the main activity as a new
- // task. Sets the the refreshDisplay flag to "true" to indicate that
- // the main activity should update its display.
- // The main activity queries the PreferenceManager to get the latest settings.
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- // Sets refreshDisplay to true so that when the user returns to the main
- // activity, the display refreshes to reflect the new settings.
- NetworkActivity.refreshDisplay = true;
- }
- }
响应网络变动
如果有一个匹配发生在设置和设备的网络连接(例如,如果设置为“wi - fi”和设备有一个wi - fi连接)之间,应用程序下载提继续并刷新显示
- public class NetworkActivity extends Activity {
- public static final String WIFI = "Wi-Fi";
- public static final String ANY = "Any";
- private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
- // Whether there is a Wi-Fi connection.
- private static boolean wifiConnected = false;
- // Whether there is a mobile connection.
- private static boolean mobileConnected = false;
- // Whether the display should be refreshed.
- public static boolean refreshDisplay = true;
- // The user's current network preference setting.
- public static String sPref = null;
- // The BroadcastReceiver that tracks network connectivity changes.
- private NetworkReceiver receiver = new NetworkReceiver();
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // Registers BroadcastReceiver to track network connection changes.
- IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
- receiver = new NetworkReceiver();
- this.registerReceiver(receiver, filter);
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- // Unregisters BroadcastReceiver when app is destroyed.
- if (receiver != null) {
- this.unregisterReceiver(receiver);
- }
- }
- // Refreshes the display if the network connection and the
- // pref settings allow it.
- @Override
- public void onStart () {
- super.onStart();
- // Gets the user's network preference settings
- SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- // Retrieves a string value for the preferences. The second parameter
- // is the default value to use if a preference value is not found.
- sPref = sharedPrefs.getString("listPref", "Wi-Fi");
- updateConnectedFlags();
- if(refreshDisplay){
- loadPage();
- }
- }
- // Checks the network connection and sets the wifiConnected and mobileConnected
- // variables accordingly.
- public void updateConnectedFlags() {
- ConnectivityManager connMgr = (ConnectivityManager)
- getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
- if (activeInfo != null && activeInfo.isConnected()) {
- wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
- mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
- } else {
- wifiConnected = false;
- mobileConnected = false;
- }
- }
- // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
- public void loadPage() {
- if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
- || ((sPref.equals(WIFI)) && (wifiConnected))) {
- // AsyncTask subclass
- new DownloadXmlTask().execute(URL);
- } else {
- showErrorPage();
- }
- }
- ...
- }
检测网络连接变化
- public class NetworkReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- ConnectivityManager conn = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = conn.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();
- }
- }
三、解析xml
上传和解析XML数据是很常见的任务,网络连接应用程序。这一课解释了如何解析XML文档并使用他们的数据
选择转换器
我们建议XmlPullParser,这是一种高效且可维护的方式来解析XML在Android里。
分析需求
- <?xml version="1.0" encoding="utf-8"?>
- <feed xmlns="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" ...">
- <title type="text">newest questions tagged android - Stack Overflow</title>
- ...
- <entry>
- ...
- </entry>
- <entry>
- <id>http://stackoverflow.com/q/9439999</id>
- <re:rank scheme="http://stackoverflow.com">0</re:rank>
- <title type="text">Where is my data file?</title>
- <category scheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags" term="android"/>
- <category scheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags" term="file"/>
- <author>
- <name>cliff2310</name>
- <uri>http://stackoverflow.com/users/1128925</uri>
- </author>
- <link rel="alternate" href="http://stackoverflow.com/questions/9439999/where-is-my-data-file" />
- <published>2012-02-25T00:30:54Z</published>
- <updated>2012-02-25T00:30:54Z</updated>
- <summary type="html">
- <p>I have an Application that requires a data file...</p>
- </summary>
- </entry>
- <entry>
- ...
- </entry>
- ...
- </feed>
实例化转化器
- public class StackOverflowXmlParser {
- // We don't use namespaces
- private static final String ns = null;
- public List parse(InputStream in) throws XmlPullParserException, IOException {
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
- parser.setInput(in, null);
- parser.nextTag();
- return readFeed(parser);
- } finally {
- in.close();
- }
- }
- ...
- }
- 读取xml
- private List readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
- List entries = new ArrayList();
- parser.require(XmlPullParser.START_TAG, ns, "feed");
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- String name = parser.getName();
- // Starts by looking for the entry tag
- if (name.equals("entry")) {
- entries.add(readEntry(parser));
- } else {
- skip(parser);
- }
- }
- return entries;
- }
下面这个代码片段展示了如何解析器解析条目、标题、链接和总结:
- public static class Entry {
- public final String title;
- public final String link;
- public final String summary;
- private Entry(String title, String summary, String link) {
- this.title = title;
- this.summary = summary;
- this.link = link;
- }
- }
- // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them off
- // to their respective "read" methods for processing. Otherwise, skips the tag.
- private Entry readEntry(XmlPullParser parser) throws XmlPullParserException, IOException {
- parser.require(XmlPullParser.START_TAG, ns, "entry");
- String title = null;
- String summary = null;
- String link = null;
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- String name = parser.getName();
- if (name.equals("title")) {
- title = readTitle(parser);
- } else if (name.equals("summary")) {
- summary = readSummary(parser);
- } else if (name.equals("link")) {
- link = readLink(parser);
- } else {
- skip(parser);
- }
- }
- return new Entry(title, summary, link);
- }
- // Processes title tags in the feed.
- private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
- parser.require(XmlPullParser.START_TAG, ns, "title");
- String title = readText(parser);
- parser.require(XmlPullParser.END_TAG, ns, "title");
- return title;
- }
- // Processes link tags in the feed.
- private String readLink(XmlPullParser parser) throws IOException, XmlPullParserException {
- String link = "";
- parser.require(XmlPullParser.START_TAG, ns, "link");
- String tag = parser.getName();
- String relType = parser.getAttributeValue(null, "rel");
- if (tag.equals("link")) {
- if (relType.equals("alternate")){
- link = parser.getAttributeValue(null, "href");
- parser.nextTag();
- }
- }
- parser.require(XmlPullParser.END_TAG, ns, "link");
- return link;
- }
- // Processes summary tags in the feed.
- private String readSummary(XmlPullParser parser) throws IOException, XmlPullParserException {
- parser.require(XmlPullParser.START_TAG, ns, "summary");
- String summary = readText(parser);
- parser.require(XmlPullParser.END_TAG, ns, "summary");
- return summary;
- }
- // For the tags title and summary, extracts their text values.
- private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
- String result = "";
- if (parser.next() == XmlPullParser.TEXT) {
- result = parser.getText();
- parser.nextTag();
- }
- return result;
- }
- ...
- }
跳过无用的标签
- 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;
- }
- }
- }
使用xml数据
- public class NetworkActivity extends Activity {
- public static final String WIFI = "Wi-Fi";
- public static final String ANY = "Any";
- private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
- // Whether there is a Wi-Fi connection.
- private static boolean wifiConnected = false;
- // Whether there is a mobile connection.
- private static boolean mobileConnected = false;
- // Whether the display should be refreshed.
- public static boolean refreshDisplay = true;
- public static String sPref = null;
- ...
- // Uses AsyncTask to download the XML feed from stackoverflow.com.
- public void loadPage() {
- if((sPref.equals(ANY)) && (wifiConnected || mobileConnected)) {
- new DownloadXmlTask().execute(URL);
- }
- else if ((sPref.equals(WIFI)) && (wifiConnected)) {
- new DownloadXmlTask().execute(URL);
- } else {
- // show error
- }
- }
动态下载xml
- // 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.main);
- // Displays the HTML string in the UI via a WebView
- WebView myWebView = (WebView) findViewById(R.id.webview);
- myWebView.loadData(result, "text/html", null);
- }
- }
加载xml
- // Uploads XML from stackoverflow.com, parses it, and combines it with
- // HTML markup. Returns HTML string.
- private String loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException {
- InputStream stream = null;
- // Instantiate the parser
- StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser();
- List<Entry> entries = null;
- String title = null;
- String url = null;
- String summary = null;
- Calendar rightNow = Calendar.getInstance();
- DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa");
- // Checks whether the user set the preference to include summary text
- SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- boolean pref = sharedPrefs.getBoolean("summaryPref", false);
- StringBuilder htmlString = new StringBuilder();
- htmlString.append("<h3>" + getResources().getString(R.string.page_title) + "</h3>");
- htmlString.append("<em>" + getResources().getString(R.string.updated) + " " +
- formatter.format(rightNow.getTime()) + "</em>");
- try {
- stream = downloadUrl(urlString);
- entries = stackOverflowXmlParser.parse(stream);
- // Makes sure that the InputStream is closed after the app is
- // finished using it.
- } finally {
- if (stream != null) {
- stream.close();
- }
- }
- // StackOverflowXmlParser returns a List (called "entries") of Entry objects.
- // Each Entry object represents a single post in the XML feed.
- // This section processes the entries list to combine each entry with HTML markup.
- // Each entry is displayed in the UI as a link that optionally includes
- // a text summary.
- for (Entry entry : entries) {
- htmlString.append("<p><a href='");
- htmlString.append(entry.link);
- htmlString.append("'>" + entry.title + "</a></p>");
- // If the user set the preference t http:// o include summary text,
- // adds it to the display.
- if (pref) {
- htmlString.append(entry.summary);
- }
- }
- return htmlString.toString();
- }
- // 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 */);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- // Starts the query
- conn.connect();
- InputStream stream = conn.getInputStream();
- }
上面的片段代码为了帮助大家理解,这里还是老习惯,贴上项目的源代码,本来是有项目截图,运行效果图之类的图的,只是这篇文章太长了,再弄图片,就更占篇幅了,所以就只贴源码了,大家可以自己的运行起来看看,希望能从整体的架构和具体的代码细节上帮助到大家。点击打开下载链接