【從 0 開始開發(fā)一款直播 APP】9 網(wǎng)絡連接狀態(tài)源碼詳解

本文為菜鳥窩作者蔣志碧的連載。“從 0 開始開發(fā)一款直播 APP ”系列來聊聊時下最火的直播 APP,如何完整的實現(xiàn)一個類"騰訊直播"的商業(yè)化項目
每個程序猿必備的110本經(jīng)典編程書,免費領(lǐng)取地址:http://mp.weixin.qq.com/s/cx433vAj_CDLzmhOoUS6zA


一、前言

現(xiàn)在大多數(shù) APP 都需要從網(wǎng)絡獲取數(shù)據(jù),訪問網(wǎng)絡在所難免。但是訪問網(wǎng)絡之前,我們應該做下網(wǎng)絡狀態(tài)判斷,而不是直接使用 HTTP 訪問網(wǎng)絡。很多人開發(fā)經(jīng)常忽略這塊內(nèi)容跳過網(wǎng)絡判斷,直接訪問網(wǎng)絡,當斷網(wǎng)時,用戶不知,導致用戶體驗度差,更甚者,當訪問某個大流量數(shù)據(jù)時,用戶不希望使用移動網(wǎng)絡,而應該使用 Wi-Fi,特別是看高清電影,一部電影看下來流量估計報表,SIM 卡估計都直接負擔不起那昂貴的費用了,這時候用戶會在心里罵上千萬遍。

如果我們的 APP 在加載圖片或者大數(shù)據(jù)下載操作時,提醒用戶應該切換到 Wi-Fi 網(wǎng)絡進行操作,這樣就增加了用戶沾粘性,體驗效果也會好很多,特別是直播類 APP。判斷網(wǎng)絡連接是否良好,連接Wi-Fi還是移動網(wǎng)絡,斷網(wǎng)或者網(wǎng)絡改變該如何處理,都需要注意其細節(jié)。

二、登錄判斷網(wǎng)絡狀態(tài)

由于模擬器不支持移動網(wǎng)絡,筆者就用真機測試了,但是筆者住的地方?jīng)]有 Wi-Fi,因此若想要看 Wi-Fi 網(wǎng)絡判斷,只能通過模擬器了。真機錄屏看上去很模糊,但是也只能將就啦。

判斷移動網(wǎng)絡狀態(tài)

判斷 Wi-Fi 網(wǎng)絡狀態(tài)

三、網(wǎng)絡狀態(tài)詳解

3.1、添加權(quán)限

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

3.2、定義常量來標識幾種網(wǎng)絡類型

//Wi-Fi
public static final int NETTYPE_WIFI = 0;
//無網(wǎng)絡
public static final int NETTYPE_NONE = 1;
//2G
public static final int NETTYPE_2G = 2;
//3G
public static final int NETTYPE_3G = 3;
//4G
public static final int NETTYPE_4G = 4;

3.3、判斷網(wǎng)絡是否連接

我們在做訪問的時候都得進行判斷是否連網(wǎng)。判斷連網(wǎng)也比較簡單,就用到了兩個類。ConnectivityManager 和 NetworkInfo。

/**
 * 檢測網(wǎng)絡是否連接
 * @return
 */
public static boolean checkNetWorkState(Context context){
   boolean flag = false;
   //得到網(wǎng)絡連接信息
   manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
   //判斷網(wǎng)絡是否連接
   if (manager.getActiveNetworkInfo() != null){
      flag = manager.getActiveNetworkInfo().isAvailable();
   }
   if (flag){
        //判斷網(wǎng)絡類型
      isNetworkAvailable(context);
   }else {
      //若網(wǎng)絡未連接,則彈出提示進行設置
      setNetWork(context);
   }
   return flag;
}

3.4、判斷網(wǎng)絡類型

/**
 * 網(wǎng)絡已經(jīng)連接,判斷是 Wi-Fi 還是移動網(wǎng)絡(2G、3G、4G)
 * @return
 */
public static void isNetworkAvailable(Context context) {
   NetworkInfo.State gprs = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();
   NetworkInfo.State wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();
   if (gprs == NetworkInfo.State.CONNECTED || gprs == NetworkInfo.State.CONNECTING){
      Log.e("GPRS","移動網(wǎng)絡已打開!");
   }
   if (wifi == NetworkInfo.State.CONNECTED || wifi == NetworkInfo.State.CONNECTING){
      Log.e("WIFI","Wi-Fi已打開!");
   }
    
  //獲取網(wǎng)絡類型
   switch (getNetWorkType(context)){
      case Constants.NETTYPE_2G:
         ToastUtils.showShort(context,"當前網(wǎng)絡是2G網(wǎng)絡");
         break;
      case Constants.NETTYPE_3G:
         ToastUtils.showShort(context,"當前網(wǎng)絡是3G網(wǎng)絡");
         break;
      case Constants.NETTYPE_4G:
         ToastUtils.showShort(context,"當前網(wǎng)絡是4G網(wǎng)絡");
         break;
      case Constants.NETTYPE_WIFI:
         ToastUtils.showShort(context,"當前網(wǎng)絡是wifi");
         break;
   }

}

3.5、獲取網(wǎng)絡類型

/**
 * 獲取網(wǎng)絡類型
 * @param context Context
 * @return true 表示網(wǎng)絡可用
 */
public static int getNetWorkType(Context context) {
   ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
   NetworkInfo networkInfo = manager.getActiveNetworkInfo();

   if (networkInfo != null && networkInfo.isConnected()) {
      String type = networkInfo.getTypeName();

      if (type.equalsIgnoreCase("WIFI")) {
         return Constants.NETTYPE_WIFI;//Wi-Fi網(wǎng)絡
      } else if (type.equalsIgnoreCase("MOBILE")) {
         NetworkInfo mobileInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
         if (mobileInfo != null) {
            switch (mobileInfo.getType()) {
               case ConnectivityManager.TYPE_MOBILE:// 手機網(wǎng)絡
                  switch (mobileInfo.getSubtype()) {
                      //--------------------Added in API level 1---------------------  
                      //(3G)聯(lián)通  ~ 400-7000 kbps 
                     case TelephonyManager.NETWORK_TYPE_UMTS:
                       //(2.5G) 移動和聯(lián)通  ~ 100 kbps 
                     case TelephonyManager.NETWORK_TYPE_GPRS:
                      //(2.75G) 2.5G 到 3G 的過渡  移動和聯(lián)通 ~ 50-100 kbps 
                     case TelephonyManager.NETWORK_TYPE_EDGE:
                      //-----------------Added in API level 4---------------------  
                      //( 3G )電信   ~ 400-1000 kbps 
                     case TelephonyManager.NETWORK_TYPE_EVDO_0:
                       //(2G 電信)  ~ 14-64 kbps  
                     case TelephonyManager.NETWORK_TYPE_CDMA:
                      //(3.5G) 屬于3G過渡   ~ 600-1400 kbps  
                     case TelephonyManager.NETWORK_TYPE_EVDO_A:
                       //( 2G )  ~ 50-100 kbps  
                     case TelephonyManager.NETWORK_TYPE_1xRTT:
                     //---------------------Added in API level 5-------------------- 
                     //(3.5G )  ~ 2-14 Mbps  
                     case TelephonyManager.NETWORK_TYPE_HSDPA:
                      //( 3.5G )  ~ 1-23 Mbps 
                     case TelephonyManager.NETWORK_TYPE_HSUPA:
                      //( 3G ) 聯(lián)通  ~ 700-1700 kbps 
                     case TelephonyManager.NETWORK_TYPE_HSPA:
                     //---------------------Added in API level 8--------------------- 
                      //(2G )  ~25 kbps 
                     case TelephonyManager.NETWORK_TYPE_IDEN:
                        return Constants.NETTYPE_2G;
                     //---------------------Added in API level 9---------------------
                      //3G-3.5G  ~ 5 Mbps  
                     case TelephonyManager.NETWORK_TYPE_EVDO_B:
                     //---------------------Added in API level 11--------------------
                      //(4G) ~ 10+ Mbps  
                     case TelephonyManager.NETWORK_TYPE_LTE:
                        return Constants.NETTYPE_4G;
                      //3G(3G到4G的升級產(chǎn)物)  ~ 1-2 Mbps  
                     case TelephonyManager.NETWORK_TYPE_EHRPD:
                      //--------------------Added in API level 13------------------- 
                      //( 3G )  ~ 10-20 Mbps  
                     case TelephonyManager.NETWORK_TYPE_HSPAP:
                        return Constants.NETTYPE_3G;
                     //無網(wǎng)絡
                     default:
                        return Constants.NETTYPE_NONE;
                  }
            }
         }
      }
   }
   return Constants.NETTYPE_NONE;
}

3.6、設置網(wǎng)絡提示

/**
 * 網(wǎng)絡為連接時,設置網(wǎng)絡
 */
private static void setNetWork(final Context context) {
   AlertDialog.Builder builder = new AlertDialog.Builder(context);
   builder.setTitle("網(wǎng)絡連接提示").setMessage("網(wǎng)絡不可用,如果繼續(xù),請設置網(wǎng)絡");
   builder.setPositiveButton("設置", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
         Intent intent = null;
         /**
          * 判斷手機系統(tǒng)的版本!如果 API 大于 10 就是 3.0+
          * 因為 3.0 以上的版本的設置和 3.0 以下的設置不一樣,調(diào)用的方法不同
          */
         if (Build.VERSION.SDK_INT > 10){
            intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
         }else {
            intent = new Intent();
            ComponentName componentName = new ComponentName(
                  "com.android.settings",
                  "com.android.settings.WirelessSettings"
            );
            intent.setComponent(componentName);
            intent.setAction("android.intent.action.VIEW");
         }
         //啟動打開 Wi-Fi 設置頁面
         context.startActivity(intent);
      }
   });

   builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
            return;
      }
   });

   builder.create();
   builder.show();
}

在 Presenter 層調(diào)用該判斷網(wǎng)絡請求進行登錄操作。具體代碼在 MVP 和 MVC 中詳細講過,這里不重復粘貼代碼了。

@Override
public boolean checkUserNameLogin(String userName, String password) {
    if (OtherUtils.isUsernameVaild(userName)) {
        if (OtherUtils.isPasswordValid(password)) {
            if (OtherUtils.checkNetWorkState(mLoginView.getContext())) {
                return true;
            } else {
                mLoginView.showMsg("當前無網(wǎng)絡連接!");
            }
        } else {
            mLoginView.passwordError("密碼過短!");
        }
    } else {
        mLoginView.usernameError("用戶名不符合規(guī)范!");
    }
    mLoginView.dismissLoading();
    return false;
}

四、ConnectivityManager詳解

看到上例中主要使用到的兩個類是 ConnectivityManager 和 NetworkInfo,下面先看看 ConnectivityManager 的主要參數(shù)和方法。

ConnectivityManager 是網(wǎng)絡連接相關(guān)的管理器,它主要用于查詢網(wǎng)絡狀態(tài)并在網(wǎng)絡發(fā)生改變時發(fā)出狀態(tài)變化通知。這個類主要負責的下列四個方面:
1、監(jiān)控網(wǎng)絡狀態(tài)(包括WiFi, GPRS, UMTS等)。
2、當網(wǎng)絡連接改變時發(fā)送廣播 Intent。
3、 當一種網(wǎng)絡斷開時,試圖連接到另一種網(wǎng)絡進行故障處理。
4、 提供一系列接口讓應用程序查詢可獲得的網(wǎng)絡的粗粒度和細粒度狀態(tài)。

ConnectivityManager 比較重要的幾個類常量

類型 常量值 說明
int TYPE_BLUETOOTH 藍牙數(shù)據(jù)連接
int TYPE_ETHERNET 以太網(wǎng)數(shù)據(jù)連接
int TYPE_MOBILE 移動數(shù)據(jù)連接
int TYPE_WIFI Wi-Fi連接
int DEFAULT_NETWORK_PREFERENCE 默認網(wǎng)絡連接偏好,建議在config.xml中進行配置.并通過調(diào)用 getNetworkPreference() 獲取應用的當前設置值。
String EXTRA_EXTRA_INFO 查詢關(guān)鍵字,提供關(guān)于網(wǎng)絡狀態(tài)的信息
String EXTRA_NETWORK_INFO 建議使用getActiveNetworkInfo() or getAllNetworkInfo()獲取網(wǎng)絡連接信息
String EXTRA_NETWORK_TYPE 觸發(fā) CONNECTIVITY_ACTION廣播的網(wǎng)絡類型

ConnectivityManager 比較重要的幾個方法

返回類型 方法名
NetworkInfo getActiveNetworkInfo() 獲取當前連接可用的網(wǎng)絡
NetworkInfo[] getAllNetworkInfo() 獲取設備支持的所有網(wǎng)絡類型的鏈接狀態(tài)信息。
NetworkInfo getNetworkInfo(int networkType) 獲取特定網(wǎng)絡類型的鏈接狀態(tài)信息
int getNetworkPreference() 獲取當前偏好的網(wǎng)絡類型。
boolean isActiveNetworkMetered() 返回當前被計量的活動的數(shù)據(jù)網(wǎng)絡
static boolean isNetworkTypeValid(int networkType) 判斷給定的數(shù)值是否表示一種網(wǎng)絡
boolean requestRouteToHost(int networkType, int hostAddress) 確保存在通過指定網(wǎng)絡接口將流量傳輸?shù)街付ㄖ鳈C的網(wǎng)絡路由。
void setNetworkPreference(int preference) 指定首選網(wǎng)絡類型
int startUsingNetworkFeature(int networkType, String feature) 告訴呼叫者想要開始使用命名功能的底層網(wǎng)絡系統(tǒng)。
int stopUsingNetworkFeature(int networkType, String feature) 告訴使用命名功能調(diào)用者完成的底層網(wǎng)絡系統(tǒng)。

五、NetworkInfo 詳解

NetworkInfo 是一個描述網(wǎng)絡狀態(tài)的接口,可通過 ConnectivityManager 調(diào)用 getActiveNetworkInfo() 獲得當前連接的網(wǎng)絡類型。

NetworkInfo 有兩個枚舉類型的成員變量 NetworkInfo.DetailedState 和 NetworkInfo.State,用于查看當前網(wǎng)絡的狀態(tài)。其中 NetworkInfo.State的值包括:

類型 狀態(tài)值 說明
NetworkInfo.State CONNECTED 已連接
NetworkInfo.State CONNECTING 正在連接
NetworkInfo.State DISCONNECTED 已斷開鏈接
NetworkInfo.State DISCONNECTING 正在斷開鏈接
NetworkInfo.State SUSPENDED 暫停/掛起
NetworkInfo.State UNKNOWN 未知

NetworkInfo 還包括一系列可用的方法用于判斷當前網(wǎng)絡是否可用,如下:

返回類型 方法名
NetworkInfo.DetailedState getDetailedState() 獲取當前細粒度的網(wǎng)絡狀態(tài)。
String getExtraInfo() 報告關(guān)于網(wǎng)絡狀態(tài)的額外信息( 如果有的話由下層網(wǎng)絡層提供),如果有一個可用
String getReason() 如果數(shù)據(jù)網(wǎng)絡連接可用,但是連接失敗,則通過此方法可獲得嘗試鏈接失敗的原因
boolean isAvailable() 判斷當前網(wǎng)絡是否可用
boolean isConnected() 判斷當前網(wǎng)絡是否存在,并可用于數(shù)據(jù)傳輸
boolean isConnectedOrConnecting() 判斷網(wǎng)絡已連接或正在連接
boolean isFailover() 指示當前試圖連接到的網(wǎng)絡是否由 ConnectivityManager 嘗試斷開與其它網(wǎng)絡的連接
String toString() 返回一個包含該網(wǎng)絡的簡單的易懂的字符串描述。

一般來說很少用到所有的內(nèi)容,上面也只是寫出一些可能用到的方法和變量。

具體使用在文章前面已經(jīng)寫了,主要是判斷網(wǎng)絡是否連接,判斷網(wǎng)絡類型,獲取網(wǎng)絡類型等。

每個程序猿必備的110本經(jīng)典編程書,免費領(lǐng)取地址:http://mp.weixin.qq.com/s/cx433vAj_CDLzmhOoUS6zA

參考:
https://my.oschina.net/lzan13/blog/133092
http://blog.csdn.net/ls703/article/details/45823485
http://blog.csdn.net/nanzhiwen666/article/details/8288433#
http://blog.csdn.net/oyangyujun/article/details/41723865

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容