12.查詢網路連線狀態
12.1 問題
應用程式需要監控網路連線狀態的變化。
12.2 解決方案
(API Level 1)
通過ConnectivityManager監控裝置的網路連線裝置。在移動應用程式的設計過程中,需要考慮的一個很重要的問題就是網路並不是隨時都是連通的。隨著人的移動,網路的速度和容量都在不斷地變化。正因為如此,使用網路資源的應用程式需要隨時監控這些資源是否可訪問,並不能訪問時通知使用者。
除了連通性,ConnectivityManager還能嚮應用程式提供網路連線的型別。這樣就能根據情況決定是否要下載大檔案,如果使用者處於漫遊狀態的話,下載大檔案會使資料流量暴增。
12.3 實現機制
以下程式碼清單封裝了一個方法,可以把它放到你的程式碼中來檢查網路的連通性。
ConnectivityManager 封裝方法
public boolean isNetworkReachable() { final ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo current = mManager.getActiveNetworkInfo(); if(current == null) { return false; } return (current.getState() == NetworkInfo.State.CONNECTED); }
ConnectivityManager所做的工作是評估哪個網路資料介面被認為是活躍的(Wi-Fi或蜂窩網路)。在最簡單的情況下,我們僅檢查給定介面是否已連線。注意:如果沒有可用的活躍資料連線,ConnectivityManager.getActiveNetworkInfo()會返回null,所以首先要檢查這種情況。如果有可用的網路,就可以檢查其狀態,可能的返回值如下:
- DISCONNECTED
- CONNTECTING
- CONNECTED
- DISCONNECTING
如果返回的狀態是CONNECTED,網路就是穩定的,可以用來訪問遠端資源。
1. 驗證路線
移動裝置有多條連線路線(Wi-Fi、3G/4G等),並且裝置經常連線到沒有外部Web路線的網路;Wi-Fi網路尤其如此。ConnectivityManager僅僅通知使用者其裝置是否已關聯特定的網路,但不會表明該網路是否能夠訪問外部IP地址。因此,當設備嘗試通過已“連線”但沒有有效路線的網路進行連線時,網路棧就會花費幾分鐘的時間超時並適當失敗。
在某些情況下,更加智慧的方法是檢查有效的Internet連線,而非僅檢查與網路的關聯。以下程式碼清單以前面的連通性檢查為基礎,用於檢查Internet連線。
更加智慧的ConnectivityManager封裝方法
public static boolean isNetworkReachable(Context context){ final ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); final NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); //如果沒有與網路關聯,則在此處進行關聯 boolean connected = (null != activeNetworkInfo && activeNetworkInfo.isConnected()){ if (!connected) return false; //檢查是否可以訪問遠端伺服器 boolean routeExists; try{ //檢查Google公共DNS InetAddress host = InetAddress.getByName("8.8.8.8"); Socket s = new Socket(); s.connect(new InetSocketAddress(host,53),5000); //如果沒有丟擲異常,則DNS存在 routeExists = true; s.close(); }catch (IOException e){ routeExists = false; } return (connected && routeExists); }
如往常一樣驗證相同的連通性條件之後,上面的程式碼清單進一步嘗試開啟套接字(具有5秒的超時),該套接字指向Google公共DNS的眾所周知的標準IPv4標準(8.8.8.8)。如果成功連線此主機,我們就能夠確信裝置可以訪問任何啟用的Internet資源。相比於直接全面連線遠端伺服器,此方法的優勢是程式碼將更快地失敗,強制最多5秒的延遲,然後就立刻告訴使用者,我們實際上並沒有自認為已具備的Internet連線。
當網路請求失敗時,最好檢查網路的連通性,告知使用者請求失敗是網路問題。以下程式碼清單中的示例演示瞭如何在網路訪問失敗時檢查網路的連通性。
告知使用者網路不通
try{ //嘗試訪問網路資源時,如果失敗,可能會丟擲HttpResponseException或其他IOException }catch(Exception e){ if( !isNetworkReachable() ){ AlertDialog.Builder builder = new AlertDialog.Builder builder(context); builder.setTitle("No Network Connection"); builder.setMessage( " The Network is unavailable. " + " Please try your request again later." ); builder.setPositiveButton("OK",null); builder.create().show(); } }
2. 判斷連線型別
在某些情況下,應用程式還必須知道使用者所連線的網路是否是按流量收費的,可以呼叫活動網路連線的NetworkInfo.getType()方法以獲取相關資訊(參見以下程式碼)。
ConnectivityManager頻寬檢查
public booleanisWifiReachable(){ ConnectivityManager mManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo current = mManager.getActiveNetworkInfo(); if (current == null){ return false; } return (current.getType() == ConnectivityManager.TYPE_WIFI); }
這個修改後的連通性檢查版本能夠判斷使用者是否連線到了Wi-Fi網路,如果連線的是Wi-Fi網路,通常就意味著網速比較快,而且流量是免費的。