執行網路操作
這一部分闡述了如何來進行最基本的網路連接任務,管理網路連接(包含網路狀態的改變),還有讓使用者來管理一個應用網路的用法,還有描述了如何來解析和運用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資料的解析也需要更好的進行最佳化,以更快的速度把資料展現在使用者面前,這些都是很好的實踐。
Sample:http://www.android-doc.com/training/basics/network-ops/index.html