【从 0 开始开发一款直播 APP】9 网络连接状态源码详解

本文为菜鸟窝作者蒋志碧的连载。“从 0 开始开发一款直播 APP ”系列来聊聊时下最火的直播 APP,如何完整的实现一个类"腾讯直播"的商业化项目
每个程序猿必备的110本经典编程书,免费领取地址:http://mp.weixin.qq.com/s/cx433vAj_CDLzmhOoUS6zA


一、前言

现在大多数 APP 都需要从网络获取数据,访问网络在所难免。但是访问网络之前,我们应该做下网络状态判断,而不是直接使用 HTTP 访问网络。很多人开发经常忽略这块内容跳过网络判断,直接访问网络,当断网时,用户不知,导致用户体验度差,更甚者,当访问某个大流量数据时,用户不希望使用移动网络,而应该使用 Wi-Fi,特别是看高清电影,一部电影看下来流量估计报表,SIM 卡估计都直接负担不起那昂贵的费用了,这时候用户会在心里骂上千万遍。

如果我们的 APP 在加载图片或者大数据下载操作时,提醒用户应该切换到 Wi-Fi 网络进行操作,这样就增加了用户沾粘性,体验效果也会好很多,特别是直播类 APP。判断网络连接是否良好,连接Wi-Fi还是移动网络,断网或者网络改变该如何处理,都需要注意其细节。

二、登录判断网络状态

由于模拟器不支持移动网络,笔者就用真机测试了,但是笔者住的地方没有 Wi-Fi,因此若想要看 Wi-Fi 网络判断,只能通过模拟器了。真机录屏看上去很模糊,但是也只能将就啦。

判断移动网络状态

判断 Wi-Fi 网络状态

三、网络状态详解

3.1、添加权限

<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、定义常量来标识几种网络类型

//Wi-Fi
public static final int NETTYPE_WIFI = 0;
//无网络
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、判断网络是否连接

我们在做访问的时候都得进行判断是否连网。判断连网也比较简单,就用到了两个类。ConnectivityManager 和 NetworkInfo。

/**
 * 检测网络是否连接
 * @return
 */
public static boolean checkNetWorkState(Context context){
   boolean flag = false;
   //得到网络连接信息
   manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
   //判断网络是否连接
   if (manager.getActiveNetworkInfo() != null){
      flag = manager.getActiveNetworkInfo().isAvailable();
   }
   if (flag){
        //判断网络类型
      isNetworkAvailable(context);
   }else {
      //若网络未连接,则弹出提示进行设置
      setNetWork(context);
   }
   return flag;
}

3.4、判断网络类型

/**
 * 网络已经连接,判断是 Wi-Fi 还是移动网络(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","移动网络已打开!");
   }
   if (wifi == NetworkInfo.State.CONNECTED || wifi == NetworkInfo.State.CONNECTING){
      Log.e("WIFI","Wi-Fi已打开!");
   }
    
  //获取网络类型
   switch (getNetWorkType(context)){
      case Constants.NETTYPE_2G:
         ToastUtils.showShort(context,"当前网络是2G网络");
         break;
      case Constants.NETTYPE_3G:
         ToastUtils.showShort(context,"当前网络是3G网络");
         break;
      case Constants.NETTYPE_4G:
         ToastUtils.showShort(context,"当前网络是4G网络");
         break;
      case Constants.NETTYPE_WIFI:
         ToastUtils.showShort(context,"当前网络是wifi");
         break;
   }

}

3.5、获取网络类型

/**
 * 获取网络类型
 * @param context Context
 * @return true 表示网络可用
 */
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网络
      } else if (type.equalsIgnoreCase("MOBILE")) {
         NetworkInfo mobileInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
         if (mobileInfo != null) {
            switch (mobileInfo.getType()) {
               case ConnectivityManager.TYPE_MOBILE:// 手机网络
                  switch (mobileInfo.getSubtype()) {
                      //--------------------Added in API level 1---------------------  
                      //(3G)联通  ~ 400-7000 kbps 
                     case TelephonyManager.NETWORK_TYPE_UMTS:
                       //(2.5G) 移动和联通  ~ 100 kbps 
                     case TelephonyManager.NETWORK_TYPE_GPRS:
                      //(2.75G) 2.5G 到 3G 的过渡  移动和联通 ~ 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 ) 联通  ~ 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的升级产物)  ~ 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;
                     //无网络
                     default:
                        return Constants.NETTYPE_NONE;
                  }
            }
         }
      }
   }
   return Constants.NETTYPE_NONE;
}

3.6、设置网络提示

/**
 * 网络为连接时,设置网络
 */
private static void setNetWork(final Context context) {
   AlertDialog.Builder builder = new AlertDialog.Builder(context);
   builder.setTitle("网络连接提示").setMessage("网络不可用,如果继续,请设置网络");
   builder.setPositiveButton("设置", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
         Intent intent = null;
         /**
          * 判断手机系统的版本!如果 API 大于 10 就是 3.0+
          * 因为 3.0 以上的版本的设置和 3.0 以下的设置不一样,调用的方法不同
          */
         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 层调用该判断网络请求进行登录操作。具体代码在 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("当前无网络连接!");
            }
        } else {
            mLoginView.passwordError("密码过短!");
        }
    } else {
        mLoginView.usernameError("用户名不符合规范!");
    }
    mLoginView.dismissLoading();
    return false;
}

四、ConnectivityManager详解

看到上例中主要使用到的两个类是 ConnectivityManager 和 NetworkInfo,下面先看看 ConnectivityManager 的主要参数和方法。

ConnectivityManager 是网络连接相关的管理器,它主要用于查询网络状态并在网络发生改变时发出状态变化通知。这个类主要负责的下列四个方面:
1、监控网络状态(包括WiFi, GPRS, UMTS等)。
2、当网络连接改变时发送广播 Intent。
3、 当一种网络断开时,试图连接到另一种网络进行故障处理。
4、 提供一系列接口让应用程序查询可获得的网络的粗粒度和细粒度状态。

ConnectivityManager 比较重要的几个类常量

类型 常量值 说明
int TYPE_BLUETOOTH 蓝牙数据连接
int TYPE_ETHERNET 以太网数据连接
int TYPE_MOBILE 移动数据连接
int TYPE_WIFI Wi-Fi连接
int DEFAULT_NETWORK_PREFERENCE 默认网络连接偏好,建议在config.xml中进行配置.并通过调用 getNetworkPreference() 获取应用的当前设置值。
String EXTRA_EXTRA_INFO 查询关键字,提供关于网络状态的信息
String EXTRA_NETWORK_INFO 建议使用getActiveNetworkInfo() or getAllNetworkInfo()获取网络连接信息
String EXTRA_NETWORK_TYPE 触发 CONNECTIVITY_ACTION广播的网络类型

ConnectivityManager 比较重要的几个方法

返回类型 方法名
NetworkInfo getActiveNetworkInfo() 获取当前连接可用的网络
NetworkInfo[] getAllNetworkInfo() 获取设备支持的所有网络类型的链接状态信息。
NetworkInfo getNetworkInfo(int networkType) 获取特定网络类型的链接状态信息
int getNetworkPreference() 获取当前偏好的网络类型。
boolean isActiveNetworkMetered() 返回当前被计量的活动的数据网络
static boolean isNetworkTypeValid(int networkType) 判断给定的数值是否表示一种网络
boolean requestRouteToHost(int networkType, int hostAddress) 确保存在通过指定网络接口将流量传输到指定主机的网络路由。
void setNetworkPreference(int preference) 指定首选网络类型
int startUsingNetworkFeature(int networkType, String feature) 告诉呼叫者想要开始使用命名功能的底层网络系统。
int stopUsingNetworkFeature(int networkType, String feature) 告诉使用命名功能调用者完成的底层网络系统。

五、NetworkInfo 详解

NetworkInfo 是一个描述网络状态的接口,可通过 ConnectivityManager 调用 getActiveNetworkInfo() 获得当前连接的网络类型。

NetworkInfo 有两个枚举类型的成员变量 NetworkInfo.DetailedState 和 NetworkInfo.State,用于查看当前网络的状态。其中 NetworkInfo.State的值包括:

类型 状态值 说明
NetworkInfo.State CONNECTED 已连接
NetworkInfo.State CONNECTING 正在连接
NetworkInfo.State DISCONNECTED 已断开链接
NetworkInfo.State DISCONNECTING 正在断开链接
NetworkInfo.State SUSPENDED 暂停/挂起
NetworkInfo.State UNKNOWN 未知

NetworkInfo 还包括一系列可用的方法用于判断当前网络是否可用,如下:

返回类型 方法名
NetworkInfo.DetailedState getDetailedState() 获取当前细粒度的网络状态。
String getExtraInfo() 报告关于网络状态的额外信息( 如果有的话由下层网络层提供),如果有一个可用
String getReason() 如果数据网络连接可用,但是连接失败,则通过此方法可获得尝试链接失败的原因
boolean isAvailable() 判断当前网络是否可用
boolean isConnected() 判断当前网络是否存在,并可用于数据传输
boolean isConnectedOrConnecting() 判断网络已连接或正在连接
boolean isFailover() 指示当前试图连接到的网络是否由 ConnectivityManager 尝试断开与其它网络的连接
String toString() 返回一个包含该网络的简单的易懂的字符串描述。

一般来说很少用到所有的内容,上面也只是写出一些可能用到的方法和变量。

具体使用在文章前面已经写了,主要是判断网络是否连接,判断网络类型,获取网络类型等。

每个程序猿必备的110本经典编程书,免费领取地址: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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容