Android开发中判断当前网络是否可上网,而不是判断是否已连接

问题场景:


最近开发中遇到一个bug,在设置日期和时间时,手动设置时间,开关机时间正常.使用自动获取网络时间,连接可上网的网络,获取时间也是正常.


但在使用静态IP时或者网络不可上网时,获取的时间就是异常的.


问题分析:


代码如下:


private void setAutoTime() {
    if (isNetworkAvalible(getActivity())) {
        Log.d("setRTCTime", "===setAutoTime===isNetworkAvalible====");
        final Calendar calendar = Calendar.getInstance();
        new Thread(new Runnable() {
            @Override
            public void run() {
                URL urlTime = null;//取得资源对象
                try {
                    urlTime = new URL("https://www.baidu.com");
                    URLConnection uc = urlTime.openConnection();//生成连接对象
                    uc.setConnectTimeout(3000);
                    uc.connect(); //发出连接
                    long autoTime = uc.getDate(); //取得网站日期时间
                    Date date = new Date(autoTime); //转换为标准时间对象
                    date.getDate();
                    Log.d("setRTCTime", "===setAutoTime===autoTime====" + autoTime);
                    if (autoTime == 0) {
                        return;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

public boolean isNetworkAvalible(Context context) {
// 获得网络状态管理器
    ConnectivityManager connectivityManager = (ConnectivityManager) context
        .getSystemService(Context.CONNECTIVITY_SERVICE);

    if (connectivityManager == null) {
        return false;
    } else {
        // 建立网络数组
        NetworkInfo[] net_info = connectivityManager.getAllNetworkInfo();
        if (net_info != null) {
            for (int i = 0; i < net_info.length; i++) {
                // 判断获得的网络状态是否是处于连接状态
                if (net_info[i].getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
    }
    return false;
}


Android开发中判断当前网络是否可上网,而不是判断是否已连接


以上代码初看并未发现问题,然而仔细分析发现isNetworkAvalible()方法只能判断当前网线是否接入,假如使用的是静态IP,即使网线不接,返回的也是true.问题的根本原因就是这个接口不能判断出静态IP或者网络不能上网的情况.


既然问题原因找到了,那解决办法就是:通过ping网关的方式去检测网络是否能够正常上网.


解决方法:


具体代码如下:


private void setAutoTime() {
    if (isNetworkAvalible(getActivity())) {
        Log.d("setRTCTime", "===setAutoTime===isNetworkAvalible====");
        final Calendar calendar = Calendar.getInstance();
        new Thread(new Runnable() {
            @Override
            public void run() {
                URL urlTime = null;//取得资源对象
                try {
                    boolean isNetAval = pingNetWork(getGateway());//ping网关
                    Log.d("setRTCTime", "===setAutoTime===isNetAval====" + isNetAval);
                    if(!isNetAval){
                        syncRTCTime();//网络无效使用RTC时间
                        return;
                    }
                    urlTime = new URL("https://www.baidu.com");
                    URLConnection uc = urlTime.openConnection();//生成连接对象
                    uc.setConnectTimeout(3000);
                    uc.connect(); //发出连接
                    long autoTime = uc.getDate(); //取得网站日期时间
                    Date date = new Date(autoTime); //转换为标准时间对象
                    date.getDate();
                    Log.d("setRTCTime", "===setAutoTime===autoTime====" + autoTime);
                    if (autoTime == 0) {
                        syncRTCTime();//网络获取不到时间使用RTC时间
                        return;
                    }
                    syncNetTime(autoTime); //获取到网络时间同步系统时间
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }else{
        syncRTCTime();//网络未连接使用RTC时间
    }
}

public boolean isNetworkAvalible(Context context) {
// 获得网络状态管理器
    ConnectivityManager connectivityManager = (ConnectivityManager) context
        .getSystemService(Context.CONNECTIVITY_SERVICE);

    if (connectivityManager == null) {
        return false;
    } else {
        // 建立网络数组
        NetworkInfo[] net_info = connectivityManager.getAllNetworkInfo();
        if (net_info != null) {
            for (int i = 0; i < net_info.length; i++) {
                // 判断获得的网络状态是否是处于连接状态
                if (net_info[i].getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
    }
    return false;
}

/**
 * 获取网关
 * @return
*/
private String getGateway() {
	ConnectivityManager connectivity =                 (ConnectivityManager) 
getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
		LinkProperties properties = connectivity.getLinkProperties(connectivity.getActiveNetwork());
		String ip = "0.0.0.0";
		LinkAddress linkAddress = properties.getLinkAddresses().get(1);
		for (int i = 0; i < properties.getLinkAddresses().size(); i++) {
			LinkAddress linkAddressTmp = properties.getLinkAddresses().get(i);
			String tmp = linkAddressTmp.getAddress().getHostAddress();
			if (!tmp.contains(":") && !tmp.equals("0.0.0.0")) {
				ip = tmp;
				linkAddress = linkAddressTmp;
				break;
			}
		}
		String mask = dealWithMask(linkAddress.getPrefixLength());
		String gateway = "0.0.0.0";
		for (RouteInfo info : properties.getRoutes()) {
			String tmp = info.getGateway().getHostAddress();
			//Log.d(TAG, "initDate: gateway = " + tmp);
			if (!tmp.equals("0.0.0.0") && !tmp.contains("::") && !tmp.contains(":")) {
				gateway = tmp;
				break;
			}
		}
		return gateway;
	}
	
	private String dealWithMask(int prefixLength) {
		int mask = 0xffffff << (32 - prefixLength);
		return ((mask>>24)&0xff) + "." + ((mask>>16)&0xff) + "."
		+ ((mask>>8)&0xff) + "." + (mask&0xff);
	}

	/**
	* 判断是否是 静态IP 模式
	* @return
	*/
	private static boolean isStaticIp() {
		boolean state = false;
		if (mEthernetManager == null) {
			return false;
		}
		IpConfiguration.IpAssignment ipAssignment = mEthernetManager.getConfiguration("eth0").ipAssignment;
		if (ipAssignment == IpConfiguration.IpAssignment.STATIC) {
			state = true;
		} else if (ipAssignment == IpConfiguration.IpAssignment.DHCP) {
			state = false;
		}
		return state;
	}

	/**
	* ping 网关
	* @param cIP
	* @return
	*/
	private static final boolean pingNetWork(final String cIP) {
		String result = null;
		try {
			Process p = Runtime.getRuntime().exec("ping -c 1 "+cIP);
			int status = p.waitFor();
			if (status == 0) {
				result = "success";
				return true;
			} else {
				// 场景:当静态IP时,不能上网时,p.waitFor() 返回都是false,无法判断。
				// 通过 p.getInputStream() 获取的信息进行判断
				// a、不插网线会返还字符串 ping info:From 196.168.1.128: icmp_seq=1 Destination Host Unreachable
				// b、插网线 为null ping info:
				// 缺陷:检测时间较长
				if(isStaticIp()) {
					InputStream input = p.getInputStream();
					BufferedReader in = new BufferedReader(new InputStreamReader(input));
					StringBuffer buffer = new StringBuffer();
					String line = "";
					while ((line = in.readLine()) != null) {
						buffer.append(line);
						if (line.contains("Destination Host Unreachable")) {
							result = "failed";
							break;
						}else{
							result = "success";
						}
					//Log.i(TAG, "ping info:" + line);
					}
					if(result.equals("success")) {
						return true;
					}
				}else{
					result = "failed";
				}
			}
		} catch (IOException e) {
			result = "IOException";
		} catch (InterruptedException e) {
			result = "InterruptedException";
		} finally {
			//Log.d(TAG, "ping result = " + result);
		}
		return false;
	}

	private void syncNetTime(long time){
		final Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(time);
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH);
		int day = calendar.get(Calendar.DAY_OF_MONTH);
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		int minute = calendar.get(Calendar.MINUTE);
		int sec = calendar.get(Calendar.SECOND);

		if (time / 1000 < Integer.MAX_VALUE) {
			((AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE)).setTime(time);

			yearAuto = year;
			monthAuto = month;
			dayAuto = day;
		}
		setRTCTime();
	}
	
	private void syncRTCTime(){
		final Calendar calendar = Calendar.getInstance();
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH);
		int day = calendar.get(Calendar.DAY_OF_MONTH);
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		int minute = calendar.get(Calendar.MINUTE);
		int sec = calendar.get(Calendar.SECOND);

		long when = calendar.getTimeInMillis();
		if (when / 1000 < Integer.MAX_VALUE) {
			((AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE)).setTime(when);
			yearAuto = year;
			monthAuto = month;
			dayAuto = day;
		}
		setRTCTime();
	}


Android开发中判断当前网络是否可上网,而不是判断是否已连接


目前网络上很多方法都是获取到的网络连接状态,并不能判断网络是否可以正常上网,以上方法可以解决这个问题,不过有时候ping的时候会比较慢一些.



Android开发中判断当前网络是否可上网,而不是判断是否已连接

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章