ConnectivityManager,网络链接,多网络链接绑定指定网络,监听类型
发布日期:2021-06-30 21:23:14
浏览次数:2
分类:技术文章
本文共 11789 字,大约阅读时间需要 39 分钟。
最小案例
需要的权限
MainActivity.java
public class MainActivity extends AppCompatActivity { private IntentFilter intentFilter; private NetworkChangeReceiver networkChangeReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentFilter=new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); networkChangeReceiver = new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver,intentFilter); } @Override protected void onDestroy(){ super.onDestroy(); unregisterReceiver(networkChangeReceiver); } private final class NetworkChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent){ ConnectivityManager cm=(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo= cm.getActiveNetworkInfo(); if(networkInfo == null){ // WIFI 和 移动网络都关闭 即没有有效网络 Log.e(TAG, "当前无网络连接"); return; } String typeName = ""; if(networkInfo.getType()==ConnectivityManager.TYPE_WIFI){ //WIFI网络跳转的页面. typeName = networkInfo.getTypeName();//==> WIFI }else if(networkInfo.getType()==ConnectivityManager.TYPE_MOBILE) { //无线网络跳转的页面 typeName = networkInfo.getTypeName();//==> MOBILE } Log.e(TAG, "==>" + typeName); Log.e(TAG, "==>" + networkInfo.getDetailedState()); } }}
概况
ConnectivityManager主要职责,官方说明:
- Monitor network connections (Wi-Fi, GPRS, UMTS, etc.)
- Send broadcast intents when network connectivity changes
- Attempt to "fail over" to another network when connectivity to a network is lost
- Provide an API that allows applications to query the coarse-grained or fine-grained state of the available networks
- Provide an API that allows applications to request and select networks for their data traffic
平民翻译:
- 监控网络连接(Wi-Fi, GPRS, UMTS, etc.);
- 当网络连接改变时发送Intent;
- 当连接到一个网络失败时,尝试用其他网络补救;
- 提供API给应用查询有效网络粗略或者精确的状态;
- 提供API给应用为它们的数据传输请求和选择网络;
实践概要
NetworkInfo 实践详解
名称 | 说明 |
---|---|
isConnected() | 判断网络连接是否存在 |
isAvailable() | 判断网络连接(注:isConnected为true,不代表isAvailable为true) |
getDetailedState() | (详细)报告当前网络状态 getState()报告当前网络状态 |
getExtrInfo() | 报告关于网络状态的额外信息,由较低的网络层提供的 |
getType() | 获取当前网络的类型 和ConnectivityManager.TYPE_**对比 |
getTypeName() | 获取当前网络的类型名如 “WIFI” or “MOBILE” |
<font size=10 face=STHupo color=red>注意: </font>
- isConnected() 和 isAvailable() 都为true 不能保证能正常连接到服务器,解决方案用ping命令,参考:
//ShellUtil.CommandResult result = ShellUtil.execCmd(String.format("ping -c 1 %s", ip), false);String[] command = new String[]{String.format("ping -c 1 %s", ip)};int result = -1;Process process = Runtime.getRuntime().exec(isRoot ? "su" : "sh");DataOutputStream os = new DataOutputStream(process.getOutputStream());for (String command : commands) { if (command == null) continue; os.write(command.getBytes()); os.writeBytes(LINE_SEP); os.flush();}os.writeBytes("exit" + LINE_SEP);os.flush();result = process.waitFor();
- getDetailedState/getState 直接看NetworkInfo源码getState等到的值为
public enum State { CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN}
- getExtrInfo() WIFI链接返回SSID名称,移动网络返回APN(Access Point Name),电信物联网得卡到列如:ctnet或ctwap
ConnectivityManager 实践详解
ConnectivityManager类按照其主要职能,常用方法大致可分为三类:
- 获取网络链接信息getXXX如getActiveNetwork,getDefaultProxy
- 多网络链接绑定指定网络 bindsocket和bindprocesstonetwork(6.0的系统 api>23)
- 监听类型 registerDefaultNetworkCallback/registerNetworkCallback
方法 | 详解 |
---|---|
addDefaultNetworkActiveListener | 在网络有一定量的数据传输时间隔调用,可用于链接优化 |
cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); cm.addDefaultNetworkActiveListener(new ConnectivityManager.OnNetworkActiveListener() { @Override public void onNetworkActive() { Log.e(TAG, "Active ==>"); //无论是否成功链接外网,只要有一定量的数据传输就会间隔有回调 } });
方法 | 详解 |
---|---|
bindProcessToNetwork | 多网络同时链接时指定网络链接 |
应用场景:
- 手机同时连接移动网络和本地局域网,手机所有的连接默认访问移动网络,需要手机连接本地局域网:
方法 | 详解 |
---|---|
registerNetworkCallback | 指定网络监听的内容回调 |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP/*5.0*/) { ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); // 请注意这里会有一个版本适配bug,所以请在这里添加非空判断 if (connectivityManager != null) { NetworkRequest.Builder builder = new NetworkRequest.Builder(); NetworkRequest request = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .build(); connectivityManager.registerNetworkCallback(request,new ConnectivityManager.NetworkCallback(){ /** * 网络可用的回调连接成功 * */ @Override public void onAvailable(Network network) { super.onAvailable(network); Log.e(TAG, "onAvailable ==>" + network.toString()); } /** * 实践中在网络连接正常的情况下,丢失数据会有回调 * */ @Override public void onLosing(Network network, int maxMsToLive) { super.onLosing(network, maxMsToLive); Log.e(TAG, "onLosing ==>" + network.toString() + " max==>" + maxMsToLive); } /** * 网络不可用时调用和onAvailable成对出现 */ @Override public void onLost(Network network) { super.onLost(network); Log.e(TAG, "onLost ==>" + network.toString()); } @Override public void onUnavailable() { super.onUnavailable(); Log.e(TAG, "onUnavailable ==>"); } /** * 字面直接能理解 * @param network 新连接网络 * @param networkCapabilities 新连接网络的一些能力参数 */ @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { super.onCapabilitiesChanged(network, networkCapabilities); Log.e(TAG, "onCapabilitiesChanged ==>" + networkCapabilities.toString()); //WIFI -> CELLULAR //[ Transports: CELLULAR Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&VALIDATED LinkUpBandwidth>=51200Kbps LinkDnBandwidth>=102400Kbps Specifier: <3>] //CELLULAR -> WIFI //==>[ Transports: WIFI Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED&NOT_VPN&VALIDATED LinkUpBandwidth>=1048576Kbps LinkDnBandwidth>=1048576Kbps SignalStrength: -42] } /** * 和上面类似,但是没有试出效果 */ @Override public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { super.onLinkPropertiesChanged(network, linkProperties); Log.e(TAG, "onLinkPropertiesChanged ==>" + linkProperties.toString()); } }); } }
更多监听内容设置请访问官网
Network 浅析
从源码中可以得出Network
就是一个Parcelable数据,最重要的参数是
public final int netId;
在回想一下Network
什么时候第一次获得
@Override public void onAvailable(Network network)
如果到这里还啥都不get
代码意图,那看Network提供的方法
public InetAddress[] getAllByName(String host) throws UnknownHostException { return InetAddress.getAllByNameOnNet(host, netId);}public InetAddress getByName(String host) throws UnknownHostException { return InetAddress.getByNameOnNet(host, netId);}bindSocket(Socket socket)getSocketFactory()openConnection(URL url)openConnection(URL url, Proxy proxy)
好到此我的理解是在网络连接onAvailable
成功后,返回基于netId的底层网络标识,可以基于这个Network建立一些特殊的URL访问;
实用工具
//NetUtils.java private static final int NETWORK_TYPE_GSM = 16; private static final int NETWORK_TYPE_TD_SCDMA = 17; private static final int NETWORK_TYPE_IWLAN = 18; /** * 判断网络是否可用 *需要异步 ping,如果 ping 不通就说明网络不可用
* * @param ip ip 地址(自己服务器 ip),如果为空,ip 为阿里巴巴公共 ip * @return {@code true}: 可用{@code false}: 不可用 */ public static boolean isAvailableByPing(String ip) { if (ip == null || ip.length() <= 0) { // 阿里巴巴公共 ip ip = "223.5.5.5"; } ShellUtil.CommandResult result = ShellUtil.execCmd(String.format("ping -c 1 %s", ip), false); boolean ret = result.result == 0; if (result.successMsg != null) { Log.d("NetUtil", "isAvailableByPing() called" + result.successMsg); } if (result.errorMsg != null) { Log.d("NetUtil", "isAvailableByPing() called" + result.errorMsg); } return ret; } /** * 判断移动数据是否打开 * * @return {@code true}: 是{@code false}: 否 */ public static boolean isMobileDataEnabled() { try { TelephonyManager tm = (TelephonyManager) Utils.getApp().getSystemService(Context.TELEPHONY_SERVICE); Method getMobileDataEnabledMethod = tm.getClass().getDeclaredMethod("getDataEnabled"); if (getMobileDataEnabledMethod != null) { return (boolean) getMobileDataEnabledMethod.invoke(tm); } } catch (Exception e) { e.printStackTrace(); } return false; } /** * 打开或关闭移动数据 * * @param enabled {@code true}: 打开{@code false}: 关闭 */ public static void setMobileDataEnabled(boolean enabled) { try { TelephonyManager tm = (TelephonyManager) Utils.getApp().getSystemService(Context.TELEPHONY_SERVICE); Method setMobileDataEnabledMethod = tm.getClass().getDeclaredMethod("setDataEnabled", boolean.class); if (null != setMobileDataEnabledMethod) { setMobileDataEnabledMethod.invoke(tm, enabled); } } catch (Exception e) { e.printStackTrace(); } } private enum NetworkType { // wifi NETWORK_WIFI, // 4G 网 NETWORK_4G, // 3G 网 NETWORK_3G, // 2G 网 NETWORK_2G, // 未知网络 NETWORK_UNKNOWN, // 没有网络 NETWORK_NO } /** * 获取当前网络类型 * * @return 网络类型 *
- *
- {@link NetworkType#NETWORK_WIFI } *
- {@link NetworkType#NETWORK_4G } *
- {@link NetworkType#NETWORK_3G } *
- {@link NetworkType#NETWORK_2G } *
- {@link NetworkType#NETWORK_UNKNOWN} *
- {@link NetworkType#NETWORK_NO } *
转载地址:https://liwangjiang.blog.csdn.net/article/details/88354233 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
不错!
[***.144.177.141]2024年04月27日 05时08分57秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
阿里P8大神教你十分钟构建好SpringBoot + SSM框架 成功晋升
2019-04-30
Linux运维-搭建高可用Redis缓存
2019-04-30
膜拜!阿里内部都在强推的K8S(kubernetes)学习指南,不能再详细了
2019-04-30
Linux 常用命令
2019-04-30
递归及应用
2019-04-30
Android之Handler机制篇
2019-04-30
Android之网络协议篇
2019-04-30
Android之RecyclerView篇
2019-04-30
Android之Retrofit基本用法篇
2019-04-30
Netty与网络协议资料整理
2019-04-30
Golang相关资源整理
2019-04-30
设置Golang的开发环境
2019-04-30
对HTTP/2的部分理解
2019-04-30
Golang 逃逸分析
2019-04-30
golang实现大数据量文件的排序
2019-04-30
golang中的time包
2019-04-30
golang fmt包中的占位符
2019-04-30
Docker下使用Redis
2019-04-30
Redis的主从和集群设置
2019-04-30