記一次網(wǎng)絡(luò)判斷問題

很久沒更新,換新工作后一直比較忙,也沒有什么好分享的新技術(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é)論是上面的方法能解決大部分情況下的問題,但無法解決所以問題,并不是完全可靠

其他的我需要惡補這部分的知識再來更新這篇文章。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容