最近項(xiàng)目中有一個(gè)網(wǎng)絡(luò)判斷的需求浅碾,因?yàn)榻K端只能連接wifi,wifi即使連接上也可能會(huì)出現(xiàn)不能連接網(wǎng)絡(luò)的問題,所以需要進(jìn)行網(wǎng)絡(luò)連接的判斷。
ping的相關(guān)知識(shí)
使用ping檢驗(yàn)網(wǎng)絡(luò)是否可以連接
ping就是檢測(cè)客戶端是否可以上網(wǎng)球榆。
那么我們就上代碼
該段代碼來(lái)自http://blankj.com
導(dǎo)入常用工具包compile 'com.blankj:utilcode:1.9.8'
這個(gè)里邊有各種各樣的常用的工具類,下邊的代碼是NetworkUtils
的一個(gè)方法禁筏;
/**
* 判斷網(wǎng)絡(luò)是否可用
* <p>需添加權(quán)限 {@code <uses-permission android:name="android.permission.INTERNET"/>}</p>
* <p>需要異步ping芜果,如果ping不通就說(shuō)明網(wǎng)絡(luò)不可用</p>
*
* @param ip ip地址(自己服務(wù)器ip),如果為空融师,ip為阿里巴巴公共ip
* @return {@code true}: 可用<br>{@code false}: 不可用
*/
public static boolean isAvailableByPing(String ip) {
if (ip == null || ip.length() <= 0) {
ip = "223.5.5.5";// 阿里巴巴公共ip
}
ShellUtils.CommandResult result = ShellUtils.execCmd(String.format("ping -c 1 %s", ip), false);
boolean ret = result.result == 0;
if (result.errorMsg != null) {
Log.d("NetworkUtils", "isAvailableByPing() called" + result.errorMsg);
}
if (result.successMsg != null) {
Log.d("NetworkUtils", "isAvailableByPing() called" + result.successMsg);
}
return ret;
}
這段代碼完全可以作為網(wǎng)絡(luò)檢測(cè)的使用,可是我在使用這段代碼的時(shí)候偶爾會(huì)遇到anr的問題蚁吝。出現(xiàn)anr就說(shuō)明在主線程做了耗時(shí)操作旱爆,這是我沒有將這段代碼放到子線程造成的問題。其實(shí)ping也就相當(dāng)于去請(qǐng)求網(wǎng)絡(luò)窘茁,跟普通的接口請(qǐng)求差不多怀伦,當(dāng)網(wǎng)絡(luò)比較慢的時(shí)候就會(huì)消耗時(shí)間,放在主線程就會(huì)造成anr山林。
在修改bug的時(shí)候我對(duì)這段代碼進(jìn)行了一些修改:
* 判斷網(wǎng)絡(luò)是否可用
* <p>需添加權(quán)限 {@code <uses-permission android:name="android.permission.INTERNET"/>}</p>
* <p>需要異步ping房待,如果ping不通就說(shuō)明網(wǎng)絡(luò)不可用</p>
*
* @param ip ip地址(自己服務(wù)器ip),如果為空,ip為阿里巴巴公共ip
* @return {@code true}: 可用<br>{@code false}: 不可用
*/
public static boolean isAvailableByPing(String ip) {
if (ip == null || ip.length() <= 0) {
ip = "223.5.5.5";// 阿里巴巴公共ip
}
Runtime runtime = Runtime.getRuntime();
Process ipProcess = null;
try {
//-c 后邊跟隨的是重復(fù)的次數(shù)桑孩,-w后邊跟隨的是超時(shí)的時(shí)間拜鹤,單位是秒,不是毫秒流椒,要不然也不會(huì)anr了
ipProcess = runtime.exec("ping -c 3 -w 3 "+ip);
int exitValue = ipProcess.waitFor();
Log.i("Avalible", "Process:" + exitValue);
return (exitValue == 0);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
//在結(jié)束的時(shí)候應(yīng)該對(duì)資源進(jìn)行回收
if (ipProcess != null) {
ipProcess.destroy();
}
runtime.gc();
}
return false;
}
只需要把這個(gè)方法引用到子線程中就行了敏簿,其實(shí)不引用也可以,因?yàn)樵谶@里設(shè)定了超時(shí)時(shí)間為3秒宣虾。但是最好是放到子線程里邊惯裕。
問題補(bǔ)充
上邊的代碼在Android 7.1.2中出現(xiàn)了問題,好好的WIFI連接上之后绣硝,ping不通蜻势,每次waitfor都返回1,返回一表示W(wǎng)iFi連接鹉胖,但是沒有網(wǎng)絡(luò)握玛。其實(shí)是有網(wǎng)絡(luò)的,很奇怪次员。
解決方法:
這里我獲取了ping時(shí)抓包的信息败许,判斷是否丟包為100%。如果為100%,就說(shuō)明網(wǎng)絡(luò)有問題淑蔚。不是100%說(shuō)明網(wǎng)絡(luò)連接沒問題市殷。
廢話不多說(shuō),直接上代碼刹衫!老鐵雙擊666醋寝,,哈哈??
public boolean isNetworkOnline() {
Runtime runtime = Runtime.getRuntime();
Process ipProcess = null;
try {
ipProcess = runtime.exec("ping -c 5 -w 4 223.5.5.5");
InputStream input = ipProcess.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(input));
StringBuffer stringBuffer = new StringBuffer();
String content = "";
while ((content = in.readLine()) != null) {
stringBuffer.append(content);
}
int exitValue = ipProcess.waitFor();
if (exitValue == 0) {
//WiFi連接带迟,網(wǎng)絡(luò)正常
return true;
} else {
if (stringBuffer.indexOf("100% packet loss") != -1) {
//網(wǎng)絡(luò)丟包嚴(yán)重音羞,判斷為網(wǎng)絡(luò)未連接
return false;
} else {
//網(wǎng)絡(luò)未丟包,判斷為網(wǎng)絡(luò)連接
return true;
}
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} finally {
if (ipProcess != null) {
ipProcess.destroy();
}
runtime.gc();
}
return false;
}