簡體   English   中英

如何在 Android 上檢查互聯網訪問? InetAddress 永遠不會超時

[英]How to check internet access on Android? InetAddress never times out

我有一個AsyncTask應該檢查對主機名的網絡訪問。 但是doInBackground()永遠不會超時。 有人知道嗎?

public class HostAvailabilityTask extends AsyncTask<String, Void, Boolean> {

    private Main main;

    public HostAvailabilityTask(Main main) {
        this.main = main;
    }

    protected Boolean doInBackground(String... params) {
        Main.Log("doInBackground() isHostAvailable():"+params[0]);

        try {
            return InetAddress.getByName(params[0]).isReachable(30); 
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;       
    }

    protected void onPostExecute(Boolean... result) {
        Main.Log("onPostExecute()");

        if(result[0] == false) {
            main.setContentView(R.layout.splash);
            return;
        }

        main.continueAfterHostCheck();
    }   
}

如果設備處於飛行模式(或者可能在其他沒有可用網絡的情況下), cm.getActiveNetworkInfo()將為null ,因此您需要添加一個null檢查。

修改(埃迪的解決方案)如下:

public boolean isOnline() {
    ConnectivityManager cm =
        (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getActiveNetworkInfo();
    return netInfo != null && netInfo.isConnectedOrConnecting();
}

AndroidManifest.xml以下權限添加到AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

另一個小問題,如果您在給定的時間點絕對需要網絡連接,那么使用netInfo.isConnected()而不是netInfo.isConnectedOrConnecting可能更好。 但是,我想這取決於個人用例。

網絡連接/互聯網訪問

  • isConnectedOrConnecting() (在大多數答案中使用)檢查任何網絡連接
  • 要了解這些網絡中是否有任何一個可以訪問Internet ,請使用以下方法之一

A) Ping 一個服務器(簡單)

// ICMP 
public boolean isOnline() {
    Runtime runtime = Runtime.getRuntime();
    try {
        Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
        int     exitValue = ipProcess.waitFor();
        return (exitValue == 0);
    }
    catch (IOException e)          { e.printStackTrace(); }
    catch (InterruptedException e) { e.printStackTrace(); }

    return false;
}

+可以在主線程上運行

-不適用於某些舊設備(Galays S3 等),如果沒有互聯網可用,它會阻塞一段時間。

B) 連接到 Internet 上的 Socket(高級)

// TCP/HTTP/DNS (depending on the port, 53=DNS, 80=HTTP, etc.)
public boolean isOnline() {
    try {
        int timeoutMs = 1500;
        Socket sock = new Socket();
        SocketAddress sockaddr = new InetSocketAddress("8.8.8.8", 53);

        sock.connect(sockaddr, timeoutMs);
        sock.close();

        return true;
    } catch (IOException e) { return false; }
}

+非常快(無論哪種方式),適用於所有設備,非常可靠

-不能在 UI 線程上運行

這在每個設備上都非常可靠,並且速度非常快。 它需要在單獨的任務中運行(例如ScheduledExecutorServiceAsyncTask )。

可能的問題

  • 真的夠快嗎?

    是的,非常快;-)

  • 除了在互聯網上測試某些東西之外,沒有可靠的方法來檢查互聯網嗎?

    據我所知,但讓我知道,我會編輯我的答案。

  • 如果 DNS 關閉怎么辦?

    Google DNS(例如8.8.8.8 )是世界上最大的公共 DNS。 截至 2018 年,它每天處理超過一萬億次查詢 [ 1 ]。 我們只是說,您的應用程序可能不會成為今天的話題。

  • 需要哪些權限?

     <uses-permission android:name="android.permission.INTERNET" />

    只是互聯網訪問 - 驚喜^^(順便說一句,你有沒有想過,如果沒有這個許可,這里建議的一些方法甚至可以遠程連接互聯網訪問?)

額外:一次性RxJava/RxAndroid示例(Kotlin)

fun hasInternetConnection(): Single<Boolean> {
  return Single.fromCallable {
    try {
      // Connect to Google DNS to check for connection
      val timeoutMs = 1500
      val socket = Socket()
      val socketAddress = InetSocketAddress("8.8.8.8", 53)
    
      socket.connect(socketAddress, timeoutMs)
      socket.close()
  
      true
    } catch (e: IOException) {
      false
    }
  }
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
}

///////////////////////////////////////////////////////////////////////////////////
// Usage

    hasInternetConnection().subscribe { hasInternet -> /* do something */}

額外:一次性RxJava/RxAndroid示例(Java)

public static Single<Boolean> hasInternetConnection() {
    return Single.fromCallable(() -> {
        try {
            // Connect to Google DNS to check for connection
            int timeoutMs = 1500;
            Socket socket = new Socket();
            InetSocketAddress socketAddress = new InetSocketAddress("8.8.8.8", 53);

            socket.connect(socketAddress, timeoutMs);
            socket.close();

            return true;
        } catch (IOException e) {
            return false;
        }
    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}

///////////////////////////////////////////////////////////////////////////////////
// Usage

    hasInternetConnection().subscribe((hasInternet) -> {
        if(hasInternet) {

        }else {

        }
    });

額外:一次性AsyncTask示例

注意:這顯示了如何執行請求的另一個示例。 但是,由於AsyncTask已棄用,因此應將其替換為您的應用程序的線程調度、Kotlin Coroutines、Rx、...

class InternetCheck extends AsyncTask<Void,Void,Boolean> {

    private Consumer mConsumer;
    public  interface Consumer { void accept(Boolean internet); }

    public  InternetCheck(Consumer consumer) { mConsumer = consumer; execute(); }

    @Override protected Boolean doInBackground(Void... voids) { try {
        Socket sock = new Socket();
        sock.connect(new InetSocketAddress("8.8.8.8", 53), 1500);
        sock.close();
        return true;
    } catch (IOException e) { return false; } }

    @Override protected void onPostExecute(Boolean internet) { mConsumer.accept(internet); }
}

///////////////////////////////////////////////////////////////////////////////////
// Usage

    new InternetCheck(internet -> { /* do something with boolean response */ });

無需復雜。 最簡單的框架方式就是使用ACCESS_NETWORK_STATE權限,只做一個connected方法

public boolean isOnline() {
    ConnectivityManager cm =
        (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

    return cm.getActiveNetworkInfo() != null && 
       cm.getActiveNetworkInfo().isConnectedOrConnecting();
}

如果您有特定的主機和連接類型(wifi/移動),您也可以使用requestRouteToHost

您還需要:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

在你的安卓清單中。

要讓getActiveNetworkInfo()工作,您需要將以下內容添加到清單中。

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

查看 ConnectivityManager 類。 您可以使用此類來獲取有關主機上活動連接的信息。 http://developer.android.com/reference/android/net/ConnectivityManager.html

編輯:您可以使用

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .getNetworkInfo(ConnectivityManager.TYPE_MOBILE) 

要么

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .getNetworkInfo(ConnectivityManager.TYPE_WIFI) 

並解析返回的 NetworkInfo 對象的詳細狀態枚舉

編輯 編輯:要了解您是否可以訪問主機,您可以使用

Context.getSystemService(Context.CONNECTIVITY_SERVICE)
    .requestRouteToHost(TYPE_WIFI, int hostAddress)

顯然,我使用 Context.getSystemService(Context.CONNECTIVITY_SERVICE) 作為代理說

ConnectivityManager cm = Context.getSystemService(Context.CONNECTIVITY_SERVICE);
cm.yourMethodCallHere();

檢查此代碼...它對我有用:)

public static void isNetworkAvailable(final Handler handler, final int timeout) {
    // ask fo message '0' (not connected) or '1' (connected) on 'handler'
    // the answer must be send before before within the 'timeout' (in milliseconds)

    new Thread() {
        private boolean responded = false;   
        @Override
        public void run() { 
            // set 'responded' to TRUE if is able to connect with google mobile (responds fast) 
            new Thread() {      
                @Override
                public void run() {
                    HttpGet requestForTest = new HttpGet("http://m.google.com");
                    try {
                        new DefaultHttpClient().execute(requestForTest); // can last...
                        responded = true;
                    } 
                    catch (Exception e) {
                    }
                } 
            }.start();

            try {
                int waited = 0;
                while(!responded && (waited < timeout)) {
                    sleep(100);
                    if(!responded ) { 
                        waited += 100;
                    }
                }
            } 
            catch(InterruptedException e) {} // do nothing 
            finally { 
                if (!responded) { handler.sendEmptyMessage(0); } 
                else { handler.sendEmptyMessage(1); }
            }
        }
    }.start();
}

然后,我定義處理程序:

Handler h = new Handler() {
    @Override
    public void handleMessage(Message msg) {

        if (msg.what != 1) { // code if not connected

        } else { // code if connected

        }   
    }
};

...並啟動測試:

isNetworkAvailable(h,2000); // get the answser within 2000 ms

在此鏈接中找到並修改(!):

在您的清單文件中至少添加:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

如果您正在訪問它,您可能已經擁有 INTERNET 權限。 然后允許測試連通性的布爾函數是:

private boolean checkInternetConnection() {
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    // test for connection
    if (cm.getActiveNetworkInfo() != null
            && cm.getActiveNetworkInfo().isAvailable()
            && cm.getActiveNetworkInfo().isConnected()) {
        return true;
    } else {
        Log.v(TAG, "Internet Connection Not Present");
        return false;
    }
}

我做了這個代碼,它是最簡單的,它只是一個布爾值。 通過詢問if(isOnline()){

如果有連接,並且可以連接到頁面,您將獲得狀態代碼200 (穩定連接)。

確保添加正確的INTERNETACCESS_NETWORK_STATE權限。

public boolean isOnline() {
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getActiveNetworkInfo();
    if (netInfo != null && netInfo.isConnected()) {
        try {
            URL url = new URL("http://www.google.com");
            HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
            urlc.setConnectTimeout(3000);
            urlc.connect();
            if (urlc.getResponseCode() == 200) {
                return new Boolean(true);
            }
        } catch (MalformedURLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    return false;
}

它對我有用:

要驗證網絡可用性:

private Boolean isNetworkAvailable() {
ConnectivityManager connectivityManager 
      = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting();}

要驗證互聯網訪問:

public Boolean isOnline() {
    try {
        Process p1 = java.lang.Runtime.getRuntime().exec("ping -c 1 www.google.com");
        int returnVal = p1.waitFor();
        boolean reachable = (returnVal==0);
        return reachable;
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return false;
}

方法不止一種

一、最短但效率低下的方式

只需要網絡狀態權限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

那么這個方法,

 public boolean activeNetwork () {
        ConnectivityManager cm =
                (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        boolean isConnected = activeNetwork != null &&
                activeNetwork.isConnected();

        return isConnected;

    }

正如在答案中看到的ConnectivityManager是一個解決方案,我只是在一個方法中添加了它,這是一個所有使用的簡化方法
如果有網絡訪問而不是 Internet 訪問,則ConnectivityManager返回 true,這意味着如果您的 WiFi 連接到路由器但路由器沒有互聯網,則返回 true,它檢查連接可用性

二、高效方式

需要網絡狀態和 Internet 權限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

那么這堂課,

 public class CheckInternetAsyncTask extends AsyncTask<Void, Integer, Boolean> {

        private Context context;

        public CheckInternetAsyncTask(Context context) {
            this.context = context;
        }

        @Override
        protected Boolean doInBackground(Void... params) {

            ConnectivityManager cm =
                    (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

            assert cm != null;
            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            boolean isConnected = activeNetwork != null &&
                    activeNetwork.isConnected();


            if (isConnected) {
                try {
                    HttpURLConnection urlc = (HttpURLConnection)
                            (new URL("http://clients3.google.com/generate_204")
                                    .openConnection());
                    urlc.setRequestProperty("User-Agent", "Android");
                    urlc.setRequestProperty("Connection", "close");
                    urlc.setConnectTimeout(1500);
                    urlc.connect();
                    if (urlc.getResponseCode() == 204 &&
                            urlc.getContentLength() == 0)
                        return true;

                } catch (IOException e) {
                    Log.e("TAG", "Error checking internet connection", e);
                    return false;
                }
            } else {
                Log.d("TAG", "No network available!");
                return false;
            }


            return null;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            Log.d("TAG", "result" + result);

            if(result){
                // do ur code
            }

        }


    }

調用CheckInternetAsyncTask

new CheckInternetAsyncTask(getApplicationContext()).execute();

一些解釋:-

  • 你必須在AsyncTask上檢查 Internet,否則在某些情況下它會拋出android.os.NetworkOnMainThreadException

  • ConnectivityManager用於檢查網絡訪問是否為 true 發送請求(Ping)

  • 請求發送到http://clients3.google.com/generate_204 ,這個眾所周知的 URL 會返回一個帶有 HTTP 狀態 204 的空頁面,這比http://www.google.com更快、更有效,閱讀這個 如果你有網站,最好把你的網站放在你的網站上而不是谷歌上,只有當你在應用程序中使用它時

  • 超時可更改范圍(20ms -> 2000ms),常用1500ms

這是我使用的方法:

public boolean isNetworkAvailable(final Context context) {
    return ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo() != null;
}

更好的是,檢查以確保它已“連接”:

public boolean isNetworkAvailable(final Context context) {
    final ConnectivityManager connectivityManager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
    return connectivityManager.getActiveNetworkInfo() != null && connectivityManager.getActiveNetworkInfo().isConnected();
}

以下是該方法的使用方法:

if (isNetworkAvailable(context)) {
    // code here
} else {
    // code
}

需要的權限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

https://stackoverflow.com/a/16124915/950427

到目前為止,我所看到的最短和最干凈的方法應該是:

public final static boolean isConnected( Context context )
{   
   final ConnectivityManager connectivityManager = 
         (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );  
   final NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();    
   return networkInfo != null && networkInfo.isConnected();
}

PS:這不會ping任何主機,它只是檢查連接狀態,所以如果你的路由器沒有互聯網連接並且你的設備連接到它,即使你沒有互聯網,這個方法也會返回true
對於實際測試,我建議執行 HttpHead 請求(例如到 www.google.com)並檢查狀態,如果它的200 OK一切正常並且您的設備具有互聯網連接。

移動設備上的一個重要用例可確保存在實際連接。 當移動用戶使用“強制門戶”進入 Wifi 網絡時,這是一個常見問題,他們需要在其中登錄。我在后台使用此阻止功能以確保存在連接。

/*
 * Not Thread safe. Blocking thread. Returns true if it
 * can connect to URL, false and exception is logged.
 */
public boolean checkConnectionHttps(String url){
    boolean responded = false;
    HttpGet requestTest = new HttpGet(url);
    HttpParams params = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(params, 3000);
    HttpConnectionParams.setSoTimeout(params, 5000);
    DefaultHttpClient client = new DefaultHttpClient(params);
    try {
        client.execute(requestTest);
        responded = true;
    } catch (ClientProtocolException e) {
        Log.w(MainActivity.TAG,"Unable to connect to " + url + " " + e.toString());
    } catch (IOException e) {
        Log.w(MainActivity.TAG,"Unable to connect to " + url + " " + e.toString());
        e.printStackTrace();
    }
    return responded;
}

Kotlin 和協程

我已將該函數放置在具有viewModelScopeViewModel 使用可觀察到的LiveData我通知有關連接的活動。

視圖模型

 fun checkInternetConnection(timeoutMs: Int) {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                val socket = Socket()
                val socketAddress = InetSocketAddress("8.8.8.8", 53)

                socket.connect(socketAddress, timeoutMs)
                socket.close()

                _connection.postValue(true)
            }
            catch(ex: IOException) {
                _connection.postValue(false)
            }
        }
    }
 private val _connection = MutableLiveData<Boolean>()
 val connection: LiveData<Boolean> = _connection

活動

 private fun checkInternetConnection() {
     viewModel.connection.observe(this) { hasInternet ->
         if(!hasInternet) {
             //hasn't connection
         }
         else {
            //has connection
         }
     }
  }

它對我有用。 試試看。

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    try {
        URL url = new URL("http://stackoverflow.com/posts/11642475/edit" );
        //URL url = new URL("http://www.nofoundwebsite.com/" );
        executeReq(url);
        Toast.makeText(getApplicationContext(), "Webpage is available!", Toast.LENGTH_SHORT).show();
    }
    catch(Exception e) {
        Toast.makeText(getApplicationContext(), "oops! webpage is not available!", Toast.LENGTH_SHORT).show();
    }
}

private void executeReq(URL urlObject) throws IOException
{
    HttpURLConnection conn = null;
    conn = (HttpURLConnection) urlObject.openConnection();
    conn.setReadTimeout(30000);//milliseconds
    conn.setConnectTimeout(3500);//milliseconds
    conn.setRequestMethod("GET");
    conn.setDoInput(true);

    // Start connect
    conn.connect();
    InputStream response =conn.getInputStream();
    Log.d("Response:", response.toString());
}}

對我來說,檢查 Activity 類中的連接狀態不是一個好習慣,因為

ConnectivityManager cm =
    (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

應該在那里調用,或者您需要將您的 Activity 實例(上下文)下推到連接處理程序類,以便能夠檢查那里的連接狀態當沒有可用連接(wifi,網絡)時,我捕獲了UnknownHostException異常:

JSONObject jObj = null;
Boolean responded = false;
HttpGet requestForTest = new HttpGet("http://myserver.com");
try {
    new DefaultHttpClient().execute(requestForTest);
    responded = true;
} catch (UnknownHostException e) {
    jObj = new JSONObject();
    try {
        jObj.put("answer_code", 1);
        jObj.put("answer_text", "No available connection");
    } catch (Exception e1) {}
    return jObj;
} catch (IOException e) {
    e.printStackTrace();
}

通過這種方式,我可以處理這種情況以及同一個類中的其他情況(我的服務器總是用 json 字符串響應)

我使用此代碼而不是 InetAddress :

    try {

        URL url = new URL("http://"+params[0]);

        HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
        urlc.setRequestProperty("User-Agent", "Android Application:"+Z.APP_VERSION);
        urlc.setRequestProperty("Connection", "close");
        urlc.setConnectTimeout(1000 * 30); // mTimeout is in seconds
        urlc.connect();
        if (urlc.getResponseCode() == 200) {
            Main.Log("getResponseCode == 200");
            return new Boolean(true);
        }
    } catch (MalformedURLException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

此方法為您提供了一種非常快速的方法(用於實時反饋)或一種較慢的方法(用於需要可靠性的一次性檢查)的選項

public boolean isNetworkAvailable(bool SlowButMoreReliable) {
    bool Result = false; 
    try {
        if(SlowButMoreReliable){
            ConnectivityManager MyConnectivityManager = null;
            MyConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

            NetworkInfo MyNetworkInfo = null;
            MyNetworkInfo = MyConnectivityManager.getActiveNetworkInfo();

            Result = MyNetworkInfo != null && MyNetworkInfo.isConnected();

        } else
        {
            Runtime runtime = Runtime.getRuntime();
            Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");

            int i = ipProcess.waitFor();

            Result = i== 0;

        }

    } catch(Exception ex)
    {
        //Common.Exception(ex); //This method is one you should have that displays exceptions in your log
    }
    return Result;
}

您可以遍歷所有網絡連接並檢查是否至少有一個可用連接:

public boolean isConnected() {
    boolean connected = false;

    ConnectivityManager cm = 
        (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

    if (cm != null) {
        NetworkInfo[] netInfo = cm.getAllNetworkInfo();

        for (NetworkInfo ni : netInfo) {
            if ((ni.getTypeName().equalsIgnoreCase("WIFI")
                    || ni.getTypeName().equalsIgnoreCase("MOBILE"))
                    && ni.isConnected() && ni.isAvailable()) {
                connected = true;
            }

        }
    }

    return connected;
}

檢查 Android 網絡/互聯網連接狀態並不復雜。 下面的DetectConnection類將幫助您檢查此狀態:

import android.content.Context;
import android.net.ConnectivityManager;

public class DetectConnection {
    public static boolean checkInternetConnection(Context context) {
        ConnectivityManager con_manager = (ConnectivityManager) context
                                .getSystemService(Context.CONNECTIVITY_SERVICE);

        if (con_manager.getActiveNetworkInfo() != null
            && con_manager.getActiveNetworkInfo().isAvailable()
            && con_manager.getActiveNetworkInfo().isConnected()) {
                return true;
        } else {
            return false;
        }
    }
}

有關更多詳細信息,請訪問如何檢查 Android 網絡/互聯網連接狀態

最佳方法:

public static boolean isOnline() {
    try {
    InetAddress.getByName("google.com").isReachable(3);

    return true;
    } catch (UnknownHostException e){
    return false;
    } catch (IOException e){
    return false;
    }
    }

以下是我的Utils類中的代碼:

public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager connectivityManager 
              = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
public class Network {

Context context;

public Network(Context context){
    this.context = context;
}

public boolean isOnline() {
    ConnectivityManager cm =
            (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    return activeNetwork != null &&
                          activeNetwork.isConnectedOrConnecting();
}

}

您可以使用此方法來檢測網絡可用性 -

public static boolean isDeviceOnline(Context context) {
        boolean isConnectionAvail = false;
        try {
            ConnectivityManager cm = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo netInfo = cm.getActiveNetworkInfo();
            return netInfo.isConnected();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isConnectionAvail;
    }

檢查我們是否與isAvailable()連接以及是否可以與isConnected()建立連接非常重要

private static ConnectivityManager manager;

public static boolean isOnline(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    return networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected();
}

您可以確定網絡活動WiFi的類型:

public static boolean isConnectedWifi(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
}

或移動Móvil

public static boolean isConnectedMobile(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
    return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE;
}

不要忘記權限:

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
   <uses-permission android:name="android.permission.INTERNET" />

我已經應用了@Levit 提供的解決方案,並創建了不會調用額外 Http 請求的函數。

它將解決錯誤Unable to Resolve Host

public static boolean isInternetAvailable(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (activeNetwork == null) return false;

    switch (activeNetwork.getType()) {
        case ConnectivityManager.TYPE_WIFI:
            if ((activeNetwork.getState() == NetworkInfo.State.CONNECTED ||
                    activeNetwork.getState() == NetworkInfo.State.CONNECTING) &&
                    isInternet())
                return true;
            break;
        case ConnectivityManager.TYPE_MOBILE:
            if ((activeNetwork.getState() == NetworkInfo.State.CONNECTED ||
                    activeNetwork.getState() == NetworkInfo.State.CONNECTING) &&
                    isInternet())
                return true;
            break;
        default:
            return false;
    }
    return false;
}

private static boolean isInternet() {

    Runtime runtime = Runtime.getRuntime();
    try {
        Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
        int exitValue = ipProcess.waitFor();
        Debug.i(exitValue + "");
        return (exitValue == 0);
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }

    return false;
}

現在稱之為,

if (!isInternetAvailable(getActivity())) {
     //Show message
} else {
     //Perfoem the api request
}

使用 ConnectivityManager 的其他答案是錯誤的,因為擁有網絡連接並不意味着您可以訪問互聯網。 例如,用戶可能連接到咖啡店的 WiFi 門戶,但無法訪問互聯網。 要檢查互聯網是否可以訪問,您必須嘗試連接到實際服務器。 通常,當您要執行此操作時,您會想到要連接的特定服務器,因此請繼續檢查是否可以連接到該服務器。 這是檢查與服務器的連接的簡單方法。

private boolean isOnTheInternet() {
    try {
        URLConnection urlConnection = new URL("http://yourserver").openConnection();
        urlConnection.setConnectTimeout(400);
        urlConnection.connect();
        return true;
    } catch (Exception e) {
        return false;
    }
}

設置 ConnectTimeout 的原因是,否則它默認為 TCP 超時,它可能是幾秒長。

另請注意,Android 不會讓您在主線程上運行它。

我已經完成了所有的答案,我想出了我自己的答案,首先檢查互聯網是否可用,如果互聯網可用,然后它檢查它是否處於活動狀態。

我已經包含了所有必要的方法和類來檢查活動的 Internet 連接。

網絡實用程序類

public class NetworkUtils {

    public static final int STATUS_CONNECTED = 0 ;

    public static boolean isInternetAvailable(Context ctx){
        ConnectivityManager cm = (ConnectivityManager)ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    }

    public static int isInternetActiveWithPing() {
        try {
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
            int exitValue = process.waitFor();
            return exitValue;
        } catch (Exception ex) {
            return -1;
        }
    }

    public static boolean isInternetActiveWithInetAddress() {
        try {
            InetAddress inetAddress = InetAddress.getByName("www.google.com");
            return inetAddress != null && !inetAddress.toString().equals("");
        } catch (Exception ex) {
            return false;
        }
    }

    public static void displayInternetConnectionMessage(Context ctx){
        Toast.makeText(ctx, "Check Internet Connection", Toast.LENGTH_SHORT).show();
    }
}

您可以使用以下代碼檢查 Internet 是否處於活動狀態:

 private void checkInternetConnection() {
        if (NetworkUtils.isInternetAvailable(this)) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (NetworkUtils.isInternetActiveWithPing() == NetworkUtils.STATUS_CONNECTED) {
                        performNetworkingOperations();
                    } else {
                        if (NetworkUtils.isInternetActiveWithInetAddress()) {
                            performNetworkingOperations();
                        } else {
                            displayConnectionMessage();
                        }
                    }
                }
            }).start();

        } else {
            displayConnectionMessage();
        }
    }

    private void performNetworkingOperations() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, "Internet is Available", Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void displayConnectionMessage() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                NetworkUtils.displayInternetConnectionMessage(MainActivity.this);
            }
        });
    }

更新29/06/2015如果您正在使用Xamarin.Android並想要檢查連接性,則可以使用Nuget包在多個平台上為您提供此功能。 好的候選人在這里這里 [更新完]

上面的答案非常好,但它們都是Java,幾乎所有的都檢查連接。 就我而言,我需要與特定類型的連接建立連接,而我正在開發Xamarin.Android。 而且,我沒有在硬件層傳遞對我的活動Context的引用,我使用了Application Context。 所以這是我的解決方案,以防有人來這里有類似的要求。 我還沒有完成全部測試,一旦完成測試就會更新答案

using Android.App;
using Android.Content;
using Android.Net;

namespace Leopard.Mobile.Hal.Android
{
    public class AndroidNetworkHelper
    {
        public static AndroidNetworkStatus GetWifiConnectivityStatus()
        {
            return GetConnectivityStatus(ConnectivityType.Wifi);
        }

        public static AndroidNetworkStatus GetMobileConnectivityStatus()
        {
            return GetConnectivityStatus(ConnectivityType.Mobile);
        }

        #region Implementation

        private static AndroidNetworkStatus GetConnectivityStatus(ConnectivityType connectivityType)
        {
            var connectivityManager = (ConnectivityManager)Application.Context.GetSystemService(Context.ConnectivityService);
            var wifiNetworkInfo = connectivityManager.GetNetworkInfo(connectivityType);
            var result = GetNetworkStatus(wifiNetworkInfo);
            return result;
        }

        private static AndroidNetworkStatus GetNetworkStatus(NetworkInfo wifiNetworkInfo)
        {
            var result = AndroidNetworkStatus.Unknown;
            if (wifiNetworkInfo != null)
            {
                if (wifiNetworkInfo.IsAvailable && wifiNetworkInfo.IsConnected)
                {
                    result = AndroidNetworkStatus.Connected;
                }
                else
                {
                    result = AndroidNetworkStatus.Disconnected;
                }
            }
            return result;
        } 

        #endregion
    }

    public enum AndroidNetworkStatus
    {
        Connected,
        Disconnected,
        Unknown
    }

只需創建以下檢查互聯網連接的類:

public class ConnectionStatus {

    private Context _context;

    public ConnectionStatus(Context context) {
        this._context = context;
    }

    public boolean isConnectionAvailable() {
        ConnectivityManager connectivity = (ConnectivityManager) _context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null)
                for (int i = 0; i < info.length; i++)
                    if (info[i].getState() == NetworkInfo.State.CONNECTED) {
                        return true;
                    }
        }
        return false;
    }
}

這個類只包含一個返回連接狀態布爾值的方法。 因此,簡單來說,如果該方法找到了有效的 Internet 連接,則返回值為true ,否則如果找不到有效的連接,則返回false

MainActivity 中的以下方法然后調用前面描述的方法的結果,並提示用戶采取相應的行動:

public void addListenerOnWifiButton() {
        Button btnWifi = (Button)findViewById(R.id.btnWifi);

        iia = new ConnectionStatus(getApplicationContext());

        isConnected = iia.isConnectionAvailable();
        if (!isConnected) {
            btnWifi.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
                    Toast.makeText(getBaseContext(), "Please connect to a hotspot",
                            Toast.LENGTH_SHORT).show();
                }
            });
        }
        else {
            btnWifi.setVisibility(4);
            warning.setText("This app may use your mobile data to update events and get their details.");
        }
    }

在上面的代碼中,如果結果為 false,(因此沒有互聯網連接,用戶將被帶到 Android wi-fi 面板,在那里他被提示連接到一個 wi-fi 熱點。

如果您使用 API 23 或更高版本,您現在可以使用NetworkCapabilities.NET_CAPABILITY_VALIDATED檢查互聯網是否處於活動狀態,該服務由 Google 自己的 ping 服務提供支持。

ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
    @Override
    public void onLost(Network network) {
        // handle network lost
    }

    @Override
    public void onAvailable(Network network) {
        ConnectivityManager cm = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = cm.getNetworkInfo(network);
        boolean isConnected = (info != null && info.isConnectedOrConnecting());

        if (isConnected) {
            NetworkCapabilities nc = cm.getNetworkCapabilities(network);
            if (nc != null) {
                boolean isInternetValid = nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
                if (isInternetValid) {
                    // internet is valid
                }
            }
        }
    }
};

NetworkRequest request = new NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.registerNetworkCallback(request, networkCallback);

最簡單的解決方案是

在大多數情況下,如果他/她想連接到遠程服務器,他/她只會檢查互聯網連接,因此最簡單和最好的解決方案是按如下方式 ping 您的服務器。

public boolean isConnected() {
    final String command = "ping -c 1 yourExmapleDomain.com";
    boolean isConnected = false;
    try {
        isConnected = Runtime.getRuntime().exec(command).waitFor() == 0;
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return isConnected;
}

使用這個 Kotlin 擴展:

/**
 * Check whether network is available
 *
 * @param context
 * @return Whether device is connected to Network.
 */
fun Context.isNetworkAvailable(): Boolean {
    with(getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //Device is running on Marshmallow or later Android OS.
            with(getNetworkCapabilities(activeNetwork)) {
                return hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || hasTransport(
                    NetworkCapabilities.TRANSPORT_CELLULAR
                )
            }
        } else {
            activeNetworkInfo?.let {
                // connected to the internet
                @Suppress("DEPRECATION")
                return listOf(ConnectivityManager.TYPE_WIFI, ConnectivityManager.TYPE_MOBILE).contains(it.type)
            }
        }
    }
    return false
}
public static boolean isNetworkAvailable(Context ctx) {
ConnectivityManager connMgr = (ConnectivityManager)ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
if(connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected() ||
    connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isConnected()){
        return true;
}

return false;
 } 

用戶這個

擁有不止一種編碼方式真是太好了。 這是我的例子。

ConnectivityManager icheck = getSystemService(Context.CONNECTIVITY_SERVICE);

TextView tv = findViewById(R.id.textView1);

boolean wifi = icheck.getActiveNetworkInfo() != null;
        if(wifi) {
        tv.setText("Internet is on.");  
        } else {
             tv.setText("Internet is off.");    
        }

祝你好運。

我嘗試了近 5 種以上不同的 android 方法,發現這是 google 提供的最佳解決方案,尤其是針對 android:

  try {
  HttpURLConnection urlConnection = (HttpURLConnection)
  (new URL("http://clients3.google.com/generate_204")
  .openConnection());
  urlConnection.setRequestProperty("User-Agent", "Android");
  urlConnection.setRequestProperty("Connection", "close");
  urlConnection.setConnectTimeout(1500);
  urlConnection.connect();
  if (urlConnection.getResponseCode() == 204 &&
  urlConnection.getContentLength() == 0) {
  Log.d("Network Checker", "Successfully connected to internet");
  return true;
  }
  } catch (IOException e) {
  Log.e("Network Checker", "Error checking internet connection", e);
  }

它比任何其他可用的解決方案faster 、更efficient 、更accurate

public boolean isOnline() {
    boolean var = false;
    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    if ( cm.getActiveNetworkInfo() != null ) {
        var = true;
    }
    return var;
} 

我已經這樣做了。 我想有點短,更易讀。

干杯!

賽亞人

此代碼將幫助您查找互聯網是否已打開。

public final boolean isInternetOn() {
        ConnectivityManager conMgr = (ConnectivityManager) this.con
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = conMgr.getActiveNetworkInfo();
        return (info != null && info.isConnected());
}

此外,您應該提供以下權限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

如果您需要檢查互聯網連接,請使用此方法使用 ping 到服務器:

public boolean checkIntCON() {
    try {
        Process ipProcess = Runtime.getRuntime().exec("/system/bin/ping -c 1 8.8.8.8");
        return (ipProcess.waitFor() == 0);
    }
    catch (IOException e)          { e.printStackTrace(); }
    catch (InterruptedException e) { e.printStackTrace(); }
    return false;
}

您可以使用檢查通過使用端口

public boolean checkIntCON() {
    try {
        Socket sock = new Socket();
        SocketAddress sockaddr = new InetSocketAddress("8.8.8.8", 80); 
        // port will change according to protocols

        sock.connect(sockaddr, 1250);
        sock.close();

        return true;
    } catch (IOException e) { return false; }
}

這是檢查 wifi 和移動數據的互聯網連接的最簡單方法。

public static boolean isConnected(Activity _context) {
        if (_context != null) {
            ConnectivityManager connMgr = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
            if (activeInfo != null && activeInfo.isConnected()) {
                boolean wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
                boolean mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;

                if (wifiConnected || mobileConnected) {
                    Log.d(TAG, "Wifi Connected ");
                    return true;
                } else {
                    showAlert(_context,_context.getString(R.string.err_no_internet));
                    return false;
                }
            } else {
                showAlert(_context,_context.getString(R.string.err_no_internet));
                return false;
            }
        } else {
            Log.e(TAG, "networkConnectivity: Context NULL");

        }
        return false;
    }
 public static boolean isNetworkAvailable(Context context) {
    boolean flag = checkNetworkAvailable(context);

    if (!flag) {
        Log.d("", "No network available!");
    } 
    return flag;
}


private static boolean checkNetworkAvailable(Context context) {
    ConnectivityManager connectivityManager
            = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null;
}

正如 Android 文檔所建議的,在

getActiveNetworkInfo()在 Android 10 中已棄用。對於面向 Android 10(API 級別 29)及更高版本的應用,請改用NetworkCallbacks

所以,下面是我們使用到目前檢查網絡連接方式:

val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
val isConnected: Boolean = activeNetwork?.isConnectedOrConnecting == true

使用NetworkCallbacks檢查互聯網連接的新方法

第1步:

    private lateinit var connectivityManager:ConnectivityManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    }

第 2 步:創建回調:

private val callback = object : ConnectivityManager.NetworkCallback() {
    override fun onAvailable(network: Network) {
        super.onAvailable(network)
        Timber.e("Network:onAvailable")
    }

    override fun onLost(network: Network) {
        super.onLost(network)
        Timber.e("Network:onLost")
    }

}

第 3 步:注冊和取消注冊回調:

private fun registerNetworkCallback() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        connectivityManager.registerDefaultNetworkCallback(callback)
    } else {
        // Old way to check network connection
    }
}

override fun onStop() {
    unRegisterNetworkCallback()
    super.onStop()
}

private fun unRegisterNetworkCallback() {
    connectivityManager.unregisterNetworkCallback(callback)
}

在以下鏈接上結帳更新詳細信息:

https://developer.android.com/training/monitoring-device-state/connectivity-status-type

使用方法:

private fun isInternetAvailable(context: Context): Boolean {
    (context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).run {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return this.getNetworkCapabilities(this.activeNetwork)?.hasCapability(
                NetworkCapabilities.NET_CAPABILITY_INTERNET
            ) ?: false
        } else {
            (@Suppress("DEPRECATION")
            return this.activeNetworkInfo?.isConnected ?: false)
        }
    }
}

和所需的權限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Kotlin 實現

/**
* Function that uses ping, takes server name or ip as argument.
*
* @return [Double.MAX_VALUE] if server is not reachable. Average RTT if the server is reachable.
*
* Success output example
*
* PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
* 64 bytes from 8.8.8.8: icmp_seq=1 ttl=254 time=172 ms
* 64 bytes from 8.8.8.8: icmp_seq=2 ttl=254 time=166 ms
* 64 bytes from 8.8.8.8: icmp_seq=3 ttl=254 time=167 ms
* 64 bytes from 8.8.8.8: icmp_seq=4 ttl=254 time=172 ms
* 64 bytes from 8.8.8.8: icmp_seq=5 ttl=254 time=167 ms

* --- 8.8.8.8 ping statistics ---
* 5 packets transmitted, 5 received, 0% packet loss, time 4011ms
* rtt min/avg/max/mdev = 166.470/169.313/172.322/2.539 ms
*          |________________________|
* value to parse using it.split('=')[1].trim().split(' ')[0].trim().split('/')[1].toDouble()
*/
@ExperimentalStdlibApi
fun pingServerAverageRtt(host: String): Double {

    var aveRtt: Double = Double.MAX_VALUE

    try {
        // execute the command on the environment interface, timeout is set as 0.2 to get response faster.
        val pingProcess: Process = Runtime.getRuntime().exec("/system/bin/ping -i 0.2 -c 5 $host")
        // gets the input stream to get the output of the executed command
        val bufferedReader = BufferedReader(InputStreamReader(pingProcess.inputStream))

        bufferedReader.forEachLine {
            if (it.isNotEmpty() && it.contains("min/avg/max/mdev")) {  // when we get to the last line of executed ping command
                aveRtt = it.split('=')[1].trim()
                        .split(' ')[0].trim()
                        .split('/')[1].toDouble()
            }
        }
    } catch (e: IOException) {
        e.printStackTrace()
    }

    return aveRtt
}

使用示例


val latency = pingServerAverageRtt(ipString)
if (latency != Double.MAX_VALUE) { 
    //server reachable
} else {
    //server not reachable
}
if(isConnected()){
                Toast.makeText(getApplication(),"Thank you",Toast.LENGTH_SHORT).show();
        }
        else{

            AlertDialog.Builder builder =
                    new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle);
            builder.setTitle("Amar Bhat");
            builder.setMessage("Oops...You are not connected to Internet!!!");
            builder.setPositiveButton("OK", null);
            builder.setNegativeButton("Cancel", null);
            builder.show();
            //Toast.makeText(getApplication(),"You are not connected",Toast.LENGTH_SHORT).show();
        }




//And outside the class define isConnected()

 public boolean isConnected(){
        ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Activity.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
        if (networkInfo != null && networkInfo.isConnected())
            return true;
        else
            return false;
    }

// In minifest add these permission
<uses-permission android:name="android.permission.INTERNET" />

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

不要忘記將此權限添加到您的清單中:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

該線程中的大多數答案僅檢查是否有可用連接,但不檢查該連接是否有效,其他答案不是設備范圍內的,我的解決方案應該適用於每個設備。

您可以在啟動應用程序之前將我的代碼放在您的主要活動中,它會快速確定是否有實際的互聯網連接,如果有,將立即刪除對話框並啟動應用程序,如果沒有,則會彈出警報說該應用程序需要互聯網連接才能工作。

final AlertDialog alertDialog = new AlertDialog.Builder(this).create();
        alertDialog.setTitle("Checking Connection");
        alertDialog.setMessage("Checking...");
        alertDialog.show();
        new CountDownTimer(5000, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {

                new Thread(new Runnable() {
                    public void run() {
                        try {
                            URL url = new URL("http://web.mit.edu/");
                            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                            connection.setRequestMethod("GET");
                            connection.setConnectTimeout(5000);
                            isConnected = connection.getResponseCode() == HttpURLConnection.HTTP_OK;
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();

                if (isConnected == false){
                    alertDialog.setMessage("Try " +  (5 - millisUntilFinished/1000) + " of 5.");
                } else {
                    alertDialog.dismiss();
                }
            }
            @Override
            public void onFinish() {
                if (isConnected == false) {
                    alertDialog.dismiss();
                    new AlertDialog.Builder(activity)
                            .setTitle("No Internet")
                            .setMessage("Please connect to Internet first.")
                            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                    // kill the app?
                                }
                            })
                            .setIcon(android.R.drawable.ic_dialog_alert)
                            .show();
                } else {
                    // Launch the app
                }
            }
        }.start();
public boolean isNetworkAvailable(Context context) {
    ConnectivityManager connectivityManager
            = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
    return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

這是您需要的許可:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

您也可以使用以下代碼檢查互聯網:

 public class CheckInternetConnection {
        public Context context = null;

        public CheckInternetConnection(Context ctx) {
            this.context = ctx;
        }

        public boolean CheckInternet() {
            return isOnline();
        }
        public Boolean isOnline() 
        {
            try {
                if(isNetAvailable(context))
                    return true;
                else
                {
                    try {
                        URL url = new URL("http://www.google.com");
                        HttpURLConnection urlc = (HttpURLConnection) url
                                .openConnection();
                        urlc.setRequestProperty("User-Agent", "Test");
                        urlc.setRequestProperty("Connection", "close");
                        urlc.setConnectTimeout(3000); // This is time limit if the
                        // connection time limit
                        try {
                            urlc.connect();
                            Log.e("TAG", " urlc ----------" + urlc.getResponseCode());
                            if (urlc.getResponseCode() == 200) {
                                return true;
                            }
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    } catch (MalformedURLException e1) {
                        e1.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }

            return false;        
        }

         public synchronized static boolean isNetAvailable(Context context){

             try{
             boolean isNetAvailable=false;
             if ( context != null )
             {
                 ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                 if ( mgr != null )
                 {
                     boolean mobileNetwork = false;
                     boolean wifiNetwork = false;
                     boolean wiMaxNetwork = false;

                     boolean mobileNetworkConnecetd = false;
                     boolean wifiNetworkConnecetd = false;
                     boolean wiMaxNetworkConnected = false;

                     NetworkInfo mobileInfo = mgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
                     NetworkInfo wifiInfo = mgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
                     NetworkInfo wiMaxInfo = mgr.getNetworkInfo(ConnectivityManager.TYPE_WIMAX);

                     if ( mobileInfo != null )
                         mobileNetwork = mobileInfo.isAvailable();                   

                     if ( wifiInfo != null )
                         wifiNetwork = wifiInfo.isAvailable();

                     if(wiMaxInfo != null)
                         wiMaxNetwork = wiMaxInfo.isAvailable();

                     if(wifiNetwork == true)
                         wifiNetworkConnecetd = wifiInfo.isConnectedOrConnecting();
                     if(mobileNetwork == true)
                         mobileNetworkConnecetd = mobileInfo.isConnectedOrConnecting();
                     if(wiMaxNetwork == true)
                         wiMaxNetworkConnected = wiMaxInfo.isConnectedOrConnecting();

                     isNetAvailable = ( mobileNetworkConnecetd || wifiNetworkConnecetd || wiMaxNetworkConnected );
                 }
             }
             return isNetAvailable;
             }catch(NullPointerException e)
             {
                 return false;
             }catch(Exception e)
             {
                 return false;
             }
         }


    }

這是一些現代代碼,它使用AsynTask來解決當您嘗試連接主線程時 android 崩潰的問題,並為用戶引入帶有沖洗和重復選項的警報。

class TestInternet extends AsyncTask<Void, Void, Boolean> {
    @Override
    protected Boolean doInBackground(Void... params) {
        try {
            URL url = new URL("http://www.google.com");
            HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
            urlc.setConnectTimeout(3000);
            urlc.connect();
            if (urlc.getResponseCode() == 200) {
                return true;
            }
        } catch (MalformedURLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            return false;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
        }
        return false;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        if (!result) { // code if not connected
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setMessage("An internet connection is required.");
            builder.setCancelable(false);

            builder.setPositiveButton(
                    "TRY AGAIN",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                            new TestInternet().execute();
                        }
                    });


            AlertDialog alert11 = builder.create();
            alert11.show();
        } else { // code if connected
            doMyStuff();
        }
    }
}

...

new TestInternet().execute();

不要檢查 WIFI 連接或移動數據連接,而是嘗試訪問任何托管域。 這樣,您就可以檢查 WIFI/Mobile 連接是否具有連接公共互聯網的能力。

如果您的移動設備能夠連接到提供的公共域,則會返回以下內容。

boolean isReachable()
        {
            boolean connected = false;
            String instanceURL = "Your trusted domain name";
            Socket socket;
            try {
                socket = new Socket();
                SocketAddress socketAddress = new InetSocketAddress(instanceURL, 80);
                socket.connect(socketAddress, 5000);
                if (socket.isConnected()) {
                    connected = true;
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                socket = null;
            }
            return connected;
        }

希望它會有所幫助..

Android 提供了 ConnectivityManager 類來了解互聯網連接狀態。 以下方法對於了解互聯網連接狀態非常有用。

首先在AndroidManifest.xml中添加INTERNETACCESS_NETWORK_STATE權限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

然后使用以下方法檢查設備是否已連接到互聯網。 如果設備連接到互聯網,此方法將返回 true。

public boolean isInternetAvailable(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) 
    context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
    return activeNetwork != null
            && activeNetwork.isConnectedOrConnecting();
}

參考鏈接:- http://www.androidtutorialshub.com/android-check-internet-connection-status/

這是檢查互聯網連接的最佳方法。 此方法的作用是執行一系列檢查“手機是否未處於飛行模式,手機是否已連接到網絡等”。 如果所有檢查都返回 true,則該方法將從Internet 下載文件並查看內容是否與預期值匹配。

與 ping 服務器以檢查 Internet 連接的其他方法相比,此方法的優點是:

  1. Android 運行時因手機而異 - 因此您可能無法始終執行這些命令,如下所示: 為什么 ping 在某些設備上有效,而在其他設備上無效?

  2. 由於 wifi 網絡上的登錄頁面/重定向可能給人以連接的錯誤印象,因此 Ping 服務器並不總是有效。

這個答案是用 Kotlin 編寫的,並使用Fuel庫通過fetchUrlAsString方法從互聯網下載文件,但只要確保您的 HTTP 請求沒有被緩存,任何庫都可以被替換。 showConnectionWarning()hideConnectionWarning()視為相當於internet connection status = falseinternet connection status = true

private val networkReceiver = object : BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {

        val activeNetworkInfo = (context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo

        if (activeNetworkInfo != null) {
            if (activeNetworkInfo.isConnectedOrConnecting) {
                //Launches a coroutine to fetch file asynchronously 
                launch {
                    try {
                        //Downloads file from url on the internet - use any library you want here.  
                        val connectionStatus = fetchUrlAsString(<url_for_file_on_internet>)
                        //check if the contents of the file is as expected
                        if (connectionStatus == "Connected To Database") {
                            hideConnectionWarning()
                        } else {
                            showConnectionWarning()
                        }
                    } catch (e: Exception) {
                        //Catches an exception - fetchUrlAsString only throws an exception if there is no internet 
                        showConnectionWarning()
                    }
                }
            } else {
                showConnectionWarning()
            }
        } else {
            showConnectionWarning()
        }
    }
}

private suspend fun fetchUrlAsString(url: String): String = suspendCoroutine { cont ->
    url.httpGet().header(Pair("pragma", "no-cache"), Pair("cache-control", "no-cache")).responseString { _, _, result ->

        when (result) {
            is Result.Failure -> {
                cont.resumeWithException(result.getException())
            }
            is Result.Success -> {
                cont.resume(result.value)
            }
        }

    }
}

您將需要以下權限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

這是我用於可達性檢查的Kotlin版本,

Kotlin MyReachability

object MyReachability {

    private val REACHABILITY_SERVER = "http://google.com" // can be any URL you want

    private fun hasNetworkAvailable(context: Context): Boolean {
        val service = Context.CONNECTIVITY_SERVICE
        val manager = context.getSystemService(service) as ConnectivityManager?
        val network = manager?.activeNetworkInfo
        Log.d(classTag, "hasNetworkAvailable: ${(network != null)}")
        return (network != null)
    }

    fun hasInternetConnected(context: Context): Boolean {
        if (hasNetworkAvailable(context)) {
            try {
                val connection = URL(REACHABILITY_SERVER).openConnection() as HttpURLConnection
                connection.setRequestProperty("User-Agent", "Test")
                connection.setRequestProperty("Connection", "close")
                connection.connectTimeout = 1500
                connection.connect()
                Log.d(classTag, "hasInternetConnected: ${(connection.responseCode == 200)}")
                return (connection.responseCode == 200)
            } catch (e: IOException) {
                Log.e(classTag, "Error checking internet connection", e)
            }
        } else {
            Log.w(classTag, "No network available!")
        }
        Log.d(classTag, "hasInternetConnected: false")
        return false
    }
}

您甚至可以根據政策和限制將REACHABILITY_SERVER作為參數傳遞,例如,當您在中國時,您可以查看https://baidu.com而不是https://google.com

調用示例,

val webLoaderThread = Thread {
   if (MyReachability.hasInternetConnected(this)){
       runOnUiThread {
           //mWebView.loadUrl(LANDING_SERVER) // connected
       }
   } else {
       runOnUiThread {
           //showDialogNoNetwork() // not connected
       }
   }
}
webLoaderThread.start()

安卓權限

不要忘記將以下權限添加到您的AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

使用以下方法檢查互聯網連接,API 28 中也棄用了 ConnectivityManager.getActiveNetworkInfo()

@Suppress("DEPRECATION")
fun isNetworkConnected(context: Context): Boolean {
    val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
    return cm?.run {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            cm.getNetworkCapabilities(cm.activeNetwork)?.run {
                when {
                    hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
                    hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
                    hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
                    else -> false
                }
            }
        } else {
            cm.activeNetworkInfo?.run {
                when (type) {
                    ConnectivityManager.TYPE_WIFI -> true
                    ConnectivityManager.TYPE_MOBILE -> true
                    else -> false
                }
            }
        }
    } ?: false

}

還將以下權限添加到清單

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) 用於為 Android TV 開發的應用程序,其中電視可以直接連接到以太網

這是我解決此問題並檢查有效互聯網連接的解決方法,因為正如他們所說,網絡信息類無法為您提供預期的結果,並且當網絡連接但沒有互聯網時它可能會返回 true。

所以這是我基於@Levite 答案的完整解決方法

首先你必須有 AsynckTask 來檢查網絡可用性,這是我的:

public class Connectivity {
 private static final String TAG = "Connectivity";
private static boolean hasConnected = false, hasChecked = false;
private InternetListener internetListener;
private Activity activity;

public Connectivity(InternetListener internetListener, Activity activity) {
    this.internetListener = internetListener;
    this.activity = activity;
}

public void startInternetListener() {


    CheckURL checkURL = new CheckURL(activity);

    checkURL.execute();

    long startTime = System.currentTimeMillis();

    while (true) {
        if (hasChecked && hasConnected) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    internetListener.onConnected();
                }
            });

            checkURL.cancel(true);
            return;
        }

        // check if time
        if (System.currentTimeMillis() - startTime >= 1000) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    internetListener.onDisconnected();
                }
            });


            checkURL.cancel(true);
            return;
        }
    }

    //return hasConnected;
}


class CheckURL extends AsyncTask<Void, Void, Boolean> {

    private Activity activity;

    public CheckURL(Activity activity) {
        this.activity = activity;
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        if (!isNetWorkAvailable(activity)) {
            Log.i(TAG, "Internet not available!");
            return false;
        }

        int timeoutMs = 3000;

        try {
            Socket sock = new Socket();
            SocketAddress sockaddr = new InetSocketAddress("8.8.8.8", 53);
            sock.connect(sockaddr, timeoutMs);
            sock.close();
            Log.i(TAG, "Internet available :)");
            return true;

        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    protected void onPostExecute(Boolean result) {
        hasChecked = true;
        hasConnected = result;
        super.onPostExecute(result);}}
     

private static final String TAG = "Connectivity";


private static boolean isNetWorkAvailable(Activity activity) {

    ConnectivityManager connectivityManager =
            (ConnectivityManager) 
   activity.getSystemService(Activity.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo =
            null;
    if (connectivityManager != null) {
        networkInfo = 
   connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    }
    boolean isConnected;
    boolean isWifiAvailable = false;
    if (networkInfo != null) {
        isWifiAvailable = networkInfo.isAvailable();
    }
    boolean isWifiConnected = false;
    if (networkInfo != null) {
        isWifiConnected = networkInfo.isConnected();
    }
    if (connectivityManager != null) {
        networkInfo =
                connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
    }
    boolean isMobileAvailable = false;
    if (networkInfo != null) {
        isMobileAvailable = networkInfo.isAvailable();
    }
    boolean isMobileConnected = false;
    if (networkInfo != null) {
        isMobileConnected = networkInfo.isConnected();
    }
    isConnected = (isMobileAvailable && isMobileConnected) ||
            (isWifiAvailable && isWifiConnected);
    return (isConnected);}
    }}



private static boolean isNetWorkAvailable(Context context) {

    ConnectivityManager connectivityManager =
            (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo =
            null;
    if (connectivityManager != null) {
        networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    }
    boolean isConnected;
    boolean isWifiAvailable = false;
    if (networkInfo != null) {
        isWifiAvailable = networkInfo.isAvailable();
    }
    boolean isWifiConnected = false;
    if (networkInfo != null) {
        isWifiConnected = networkInfo.isConnected();
    }
    if (connectivityManager != null) {
        networkInfo =
                connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
    }
    boolean isMobileAvailable = false;
    if (networkInfo != null) {
        isMobileAvailable = networkInfo.isAvailable();
    }
    boolean isMobileConnected = false;
    if (networkInfo != null) {
        isMobileConnected = networkInfo.isConnected();
    }
    isConnected = (isMobileAvailable && isMobileConnected) ||
            (isWifiAvailable && isWifiConnected);
    return (isConnected);

}

}

之后,您應該創建另一個線程來啟動 AscnkTask 並使用 InternetListener 監聽結果。

public interface InternetListener {
void onConnected();
void onDisconnected();
}

而正在等待 AsynckTask 結果的 Thread 你可以把它放在 Utility 類中:

 private static Thread thread;

public static void startNetworkListener(Context context, InternetListener 
    internetListener) {

    if (thread == null){
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                new Connectivity(internetListener,context).startInternetListener();
            }
        });
    }

    thread.start();
 }

最后調用 startNetworkListener() 方法並監聽結果。

來自 My Utils.java 類的活動示例:

     Utils.startNetworkListener(this, new InternetListener() {
        @Override
        public void onConnected() {
           // do your work when internet available. 
        }

        @Override
        public void onDisconnected() {
          // do your work when no internet available. 
        }
    });

快樂編碼:)。

如果您想在連接丟失時顯示警報。 您可以使用以下方法。

此方法用於檢查連接一次。 首先,您必須在您的班級中創建這個。

private boolean isNetworkConnected() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        if(!(cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected())){
            showNetworkDialog();
            return false;
        }
        return true;
    }

在您的類中創建此方法作為連接偵聽器。

private void ConnectionCheck(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkRequest networkRequest = new NetworkRequest.Builder().build();
            connectivityManager.registerNetworkCallback(networkRequest, new ConnectivityManager.NetworkCallback() {
                @Override
                public void onAvailable(Network network) {
                    super.onAvailable(network);
                    Log.i("Tag", "active connection");
                }

                @Override
                public void onLost(Network network) {
                    super.onLost(network);
                    Log.i("Tag", "losing active connection");
                    isNetworkConnected();
                }
            });
        }
    }

為了顯示對話框,您可以創建 showDialog() 方法。

private void showNetworkDialog(){
    new AlertDialog.Builder(MainActivity.this)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setTitle("Connection lost?")
            .setMessage("Please check your internet connection!")
            .setCancelable(false)
            .setPositiveButton("Exit", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();
                }
            })
            .setNegativeButton("Retry", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    isNetworkConnected();
                }
            })
            .show();
}

最后,您可以在 onCreate() 方法中調用此方法。

if(isNetworkConnected()){
            ConnectionCheck();
        }

在清單文件中,您必須提及權限。

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

代碼 :

    fun isInternetConnection(): Boolean {
    var returnVal = false
    thread {
        returnVal = try {
            khttp.get("https://www.google.com/")
            true
        }catch (e:Exception){
            false
        }
    }.join()
    return returnVal
}

搖籃:

implementation 'io.karn:khttp-android:0.1.0'

我使用khttp因為它很容易使用。

因此,在上面的代碼中,如果它成功連接到 google.com,則返回 true 否則返回 false。 太簡單了。 我不明白為什么每個人都必須像這樣簡單的事情一樣編寫冗長的代碼行。

如果您使用 Firebase,則可以使用this

爪哇:

DatabaseReference connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
connectedRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        boolean connected = snapshot.getValue(Boolean.class);
        if (connected) {
            Log.d(TAG, "connected");
        } else {
            Log.d(TAG, "not connected");
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        Log.w(TAG, "Listener was cancelled");
    }
});

科特林:

val connectedRef = Firebase.database.getReference(".info/connected")
connectedRef.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        val connected = snapshot.getValue(Boolean::class.java) ?: false
        if (connected) {
            Log.d(TAG, "connected")
        } else {
            Log.d(TAG, "not connected")
        }
    }

    override fun onCancelled(error: DatabaseError) {
        Log.w(TAG, "Listener was cancelled")
    }
})

這是確保您的應用可以訪問互聯網的簡單解決方案:

static final String CHECK_INTERNET_ACCESS_URL = "https://www.google.com";

public static void isInternetAccessWorking(Context context) {

    StringRequest stringRequest = new StringRequest(Request.Method.GET, CHECK_INTERNET_ACCESS_URL,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    // Internet access is OK
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            // NO internet access
        }
    });

    Volley.newRequestQueue(context).add(stringRequest);
}

此解決方案使用 Android 的 Volley 庫,它必須在build.gradle中聲明:

implementation 'com.android.volley:volley:1.1.1'

Jetpack 撰寫/科特林

根據Levite 的回答,可以在 Jetpack Compose 中使用這個Composable

val DNS_SERVERS = listOf("8.8.8.8", "1.1.1.1", "4.2.2.4")
const val INTERNET_CHECK_DELAY = 3000L
@Composable
fun InternetAwareComposable(
    dnsServers: List<String> = DNS_SERVERS,
    delay: Long = INTERNET_CHECK_DELAY,
    successContent: (@Composable () -> Unit)? = null,
    errorContent: (@Composable () -> Unit)? = null,
    onlineChanged: ((Boolean) -> Unit)? = null
) {
    suspend fun dnsAccessible(
        dnsServer: String
    ) = try {
        withContext(Dispatchers.IO) {
            Runtime.getRuntime().exec("/system/bin/ping -c 1 $dnsServer").waitFor()
        } == 0
    } catch (e: Exception) {
        false
    }

    var isOnline by remember { mutableStateOf(false) }
    LaunchedEffect(Unit) {
        while (true) {
            isOnline = dnsServers.any { dnsAccessible(it) }
            onlineChanged?.invoke(isOnline)
            delay(delay)
        }
    }
    if (isOnline) successContent?.invoke()
    else errorContent?.invoke()
}

我在這里看到很多過時的答案,所以我決定將我的答案加入其中。

Android 10(API 級別 29 )開始, getActiveNetworkInfo()已被棄用,Google 建議我們對面向Android 10及更高版本的應用使用NetworkCallbacks

Reading network state上的文檔提供了一些關於如何使用NetworkCallback的信息,但我沒能找到一個很好的代碼示例,讓整個過程正常工作,所以這是我想出的代碼,我們在我們的應用程序中使用:

import android.content.Context
import android.net.ConnectivityManager
import android.net.LinkProperties
import android.net.Network
import android.net.NetworkCapabilities
import com.fieldontrack.kmm.common.network.ConnectivityMonitor
import com.fieldontrack.kmm.entities.connectivity.NetworkType
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

class ConnectivityMonitorImpl(appContext: Context) : ConnectivityMonitor {
    private val connectivityManager = appContext.getSystemService(ConnectivityManager::class.java)
    private val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) =
            connectivityManager.getNetworkCapabilities(network)?.let { networkCapabilities ->
                updateConnectionStatus(networkCapabilities = networkCapabilities)
                updateNetworkType(networkCapabilities = networkCapabilities)
            } ?: run {
                _isConnectedState.value = true
            }

        override fun onLost(network: Network) =
            connectivityManager.getNetworkCapabilities(network)?.let { networkCapabilities ->
                updateConnectionStatus(networkCapabilities = networkCapabilities)
                updateNetworkType(networkCapabilities = networkCapabilities)
            } ?: run {
                _isConnectedState.value = false
                _networkTypeState.value = NetworkType.Unknown
            }

        override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
        ) {
            updateConnectionStatus(networkCapabilities = networkCapabilities)
            updateNetworkType(networkCapabilities = networkCapabilities)
        }

        override fun onLinkPropertiesChanged(
            network: Network,
            linkProperties: LinkProperties
        ) = Unit
    }
    private val _isConnectedState = MutableStateFlow(false)
    private val _networkTypeState = MutableStateFlow(NetworkType.Unknown)

    override val isConnectedState: StateFlow<Boolean> = _isConnectedState
    override val networkTypeState: StateFlow<NetworkType> = _networkTypeState

    override val isConnected: Boolean
        get() = _isConnectedState.value

    override val networkType: NetworkType
        get() = _networkTypeState.value

    init {
        startMonitoring()
    }

    override fun startMonitoring() =
        connectivityManager.registerDefaultNetworkCallback(networkCallback)

    override fun stopMonitoring() =
        connectivityManager.unregisterNetworkCallback(networkCallback)

    private fun updateConnectionStatus(networkCapabilities: NetworkCapabilities) {
        val isConnected =
            networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)

        _isConnectedState.value = isConnected
    }

    private fun updateNetworkType(networkCapabilities: NetworkCapabilities) {
        val networkType = when {
            networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> NetworkType.WiFi
            networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> NetworkType.Cellular
            else -> NetworkType.Unknown
        }

        _networkTypeState.value = networkType
    }
}

ConnectivityMonitor接口非常簡單:

interface ConnectivityMonitor {
    val isConnected: Boolean
    val networkType: NetworkType

    val isConnectedState: StateFlow<Boolean>
    val networkTypeState: StateFlow<NetworkType>
    
    fun startMonitoring()
    fun stopMonitoring()
}

NetworkType只是一個簡單的枚舉:

enum class NetworkType { Unknown, Cellular, WiFi }

據我測試,無論應用程序是在后台還是前台,它都有效。

在科特林:

class UtilityMethods {
companion object {
    fun isConnected(activity: Activity): Boolean {
        val connectivityManager: ConnectivityManager =
                activity.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        return null != connectivityManager.activeNetworkInfo
    }
}}

在 Activity 類中調用 isConnected 為:

UtilityMethods.isConnected(this)

片段類內部為:

UtilityMethods.isConnected(activity)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM