很久沒更新,換新工作后一直比較忙,也沒有什么好分享的新技術(shù),就記錄一次碰到的坑。
1. 一般情況下的網(wǎng)絡(luò)判斷
一般我們開發(fā)的時候都會碰到需要判斷網(wǎng)絡(luò)狀態(tài)然后做不同邏輯的處理的需求。然后一般比較多的做法就是適應(yīng)ConnectivityManager、NetworkInfo這些方法去判斷,例如我隨便去網(wǎng)上找一段代碼
public static boolean isAvailable(Context context){
boolean isAvailable = false ;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if(networkInfo!=null && networkInfo.isAvailable()){
isAvailable = true;
}
return isAvailable;
}
一般做判斷確實是能判斷出當(dāng)前是否有網(wǎng),最直接能測試到的就是你開wifi和關(guān)wifi會得到不同的結(jié)果。
但是其實這個做法并不能去適配所有的情況,比如是你的路由器開著,但是沒網(wǎng),實際上設(shè)備是能收到這個路由器的wifi的,只是上不了網(wǎng)而已。而這種情況用上邊的方法就無法判斷出。
其實網(wǎng)上很多方法能判斷是否有網(wǎng)絡(luò),而我嘗試過很多種不同的寫法,都無法檢測出這種情況,如果有大佬確實知道能使用Android內(nèi)部的方法來判斷這種情況,還請留言給我
2.使用ping
既然正常的方法我們無法使用,那就只能使用一些黑科技了,我們可以去ping一個可靠的地址來判斷是否有網(wǎng),畢竟我們在電腦上也經(jīng)常這樣做。再隨意從網(wǎng)上找段代碼抄下來
private boolean ping() {
try {
Process process=Runtime.getRuntime().exec("/system/bin/ping -c 4 "+"www.baidu.com") ;
int status = process.waitFor();
if (status == 0) {
return true;
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
大概這種寫法,我沒試過,但這種方法是肯定能成功的,如果不成功,去網(wǎng)上抄另一份代碼就行。
那么問題來了,這樣的方法就一定可靠嗎,其實不一定可靠,比如說你得找一個可靠的ip,不然這個地址掛了的話判斷就不準(zhǔn)了。不僅如此,以我多年使用黑科技的經(jīng)驗,一般使用黑科技都會很多坑。
3.請求一個自家的接口
這可以算是一個用邏輯上去解決的方案,而且比ping可靠。按照這個思路去寫,相信很多人都會,就請求一個自家的接口,請求成功就是正常,請求失敗就沒網(wǎng)。當(dāng)然還要做更細(xì)微的判斷,總不能你家接口返回500你也把它定義成沒網(wǎng)吧。
但是一般來說,現(xiàn)在大多數(shù)Android開發(fā)使用的網(wǎng)絡(luò)請求框架都是基于okhttp的。經(jīng)過測試,我發(fā)現(xiàn),在連上wifi但無網(wǎng)的情況下去請求后臺接口,會花費很長時間,不會馬上就給到結(jié)果。
所以我們需要去設(shè)置一個超時時間,一般okhttp設(shè)置超時時間都是在OkhttpClient中設(shè)置
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(3, TimeUnit.SECONDS)
.readTimeout(3, TimeUnit.SECONDS)
但其實經(jīng)過測試你會發(fā)現(xiàn),這樣設(shè)置并沒有效果。直到我看到了一篇文章“Okhttp解析DNS超時”,是我才學(xué)蘇淺不完全熟悉網(wǎng)絡(luò)相關(guān)的知識點,但我認(rèn)為這個超時應(yīng)該指的是解析DNS的超時,而不是連接的超時,嘗試去寫
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(3, TimeUnit.SECONDS)
.readTimeout(3, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
.dns(new Dns() {
@Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
if (hostname == null) {
throw new UnknownHostException("hostname == null");
} else {
try {
FutureTask<List<InetAddress>> task = new FutureTask<>(
new Callable<List<InetAddress>>() {
@Override
public List<InetAddress> call() throws Exception {
return Arrays.asList(InetAddress.getAllByName(hostname));
}
});
new Thread(task).start();
return task.get(3000, TimeUnit.MILLISECONDS);
} catch (Exception var4) {
UnknownHostException unknownHostException =
new UnknownHostException("Broken system behaviour for dns lookup of " + hostname);
unknownHostException.initCause(var4);
throw unknownHostException;
}
}
}
})
最后發(fā)現(xiàn)這樣的做法確實有效,無網(wǎng)的情況確實能很快的返回結(jié)果。
所以我認(rèn)為判斷網(wǎng)絡(luò)請求的操作可以結(jié)合1和3,基本能解決大部分的這類問題
4.事情并沒這么簡單
你以為故事到這里就結(jié)束啦?事情遠(yuǎn)沒你想象的這么簡單,用上面的方法,能夠正常判斷出有網(wǎng)、無網(wǎng)、有wifi但無網(wǎng)這3種情況。
但是我發(fā)現(xiàn)了另一種情況,我們平時有在公共場所連接過一些網(wǎng)絡(luò),而那些網(wǎng)絡(luò)會要求你去輸入賬號密碼登錄校驗,是否授權(quán)給你上網(wǎng)。
而在那種網(wǎng)絡(luò)的情況下,依舊會存在一些概率,你請求這個你自己的接口是有網(wǎng)的,但是可能下一秒實際你的設(shè)備就斷網(wǎng)了。
實際上我們要實時監(jiān)聽網(wǎng)絡(luò)的改變情況,可以注冊系統(tǒng)的一個廣播進(jìn)行監(jiān)聽,ConnectivityManager.CONNECTIVITY_ACTION這些。
但是在這類情況下斷網(wǎng),這些廣播是沒有推送給你網(wǎng)絡(luò)狀態(tài)變化的。
不止這些情況,說不定還存在更多其他的特殊情況,所以我的結(jié)論是上面的方法能解決大部分情況下的問題,但無法解決所以問題,并不是完全可靠
其他的我需要惡補這部分的知識再來更新這篇文章。