Як перевірити доступ до Інтернету на Android? InetAddress ніколи не виходить


657

У мене з’явилося 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();
    }   
}

5
Для перевірки наявності підключення до Інтернету, мабуть, найнадійнішим способом було б пінг на одному з основних серверів імен, це можна зробити, наприклад, за допомогою if(Runtime.getRuntime().exec("/system/bin/ping -c 1 8.8.8.8").waitFor()==0) .... Дивіться мою відповідь щодо кращого втілення цього. Тим не менш, прийняту відповідь (та багато інших тут) просто перевірте на підключення до мережі , а не на Інтернет.
Левіт


4
Не використовуйте метод ping, використовуйте перевірку HTTP. ICMP блокується в деяких мережах, тому ping не працюватиме. Наприклад: він ідеально працює на моєму домашньому wifi, але це не так, коли я використовую мобільні дані в мережі Vodafone (в Угорщині). Або комбінуйте два способи як резервний, але будьте обережні, тому що waitFor () буде чекати близько 20 секунд, навіть якщо використовується -w або -W.
Tamás Bolvári

Перевірте це: stackoverflow.com/a/39766506/3806413
0xAliHn

@ TamásBolvári: Ще краще було б вирішити це на шарі tcp. Що має наблизитись до швидкості ICMP з надійністю HTTP-запиту. Я відповідно відредагував "відповідь ping".
Левіт

Відповіді:


552

Підключення до мережі / доступ до Інтернету

  • isConnectedOrConnecting()(використовується в більшості відповідей) перевіряє будь-яке мережне з'єднання
  • Щоб знати, чи має будь-яка з цих мереж доступ до Інтернету , скористайтеся одним із наведених нижче

A) Пінг-сервер (простий)

// 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) Підключення до розетки в Інтернеті (розширено)

// 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; }
}

+дуже швидко (в будь-якому випадку), працює на всіх пристроях, дуже надійно

- не може працювати на потоці інтерфейсу користувача

Це працює дуже надійно, на кожному пристрої, і дуже швидко. Це потрібно виконувати в окремому завданні (наприклад, ScheduledExecutorServiceабо AsyncTask).

Можливі запитання

  • Це справді досить швидко?

    Так, дуже швидко ;-)

  • Чи немає надійного способу перевірити Інтернет, окрім тестування чогось в Інтернеті?

    Не наскільки я знаю, але дайте мені знати, і я відредагую свою відповідь.

  • Що робити, якщо DNS не працює?

    Google DNS (наприклад 8.8.8.8) - найбільша загальнодоступна DNS у світі. Станом на 2013 рік він обслуговував 130 мільярдів запитів на день. Скажімо, ваш додаток, ймовірно, не буде сьогоднішньою розмовою.

  • Які дозволи потрібні?

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

    Просто доступ до Інтернету - сюрприз ^^ (До речі, ви коли-небудь замислювалися над тим, як деякі із запропонованих тут методів можуть мати навіть віддалений клей щодо доступу до Інтернету без цього дозволу?)

 

Додатково: AsyncTaskПриклад одним ударом

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 */ });

Додатково: RxJava/RxAndroidПриклад одним ударом (Котлін)

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 */}

22
Це прекрасний мирний код! Я вважаю це дуже корисним на пристроях, які використовують передплачені картки! Коли у них закінчуються гроші, у них є доступ до Інтернету, але немає Інтернету. Тому просто перевірити наявність підключення не обійшлося б. ДЯКУЮ ТОБІ!
Блейзер

10
Пам'ятайте, що цей підхід є блокуючим, тому не слід його виконувати в therad the UI therad
Сергій

36
@Levit Це має бути прийнята відповідь. Вище відповідь просто перевіряє мережу n НЕ ІНТЕРНЕТ ПІДТРИМКА . І так це дуже швидко. Дякую. Звідси поголовно.
Roon13

9
Це рішення працює не для всіх пристроїв. Деякі пристрої завжди повертають 2, як заявив @Salmaan. На пристроях, які я тестував, було підключення до Інтернету, а цілью ping є сервер DNS Google, який відповідає на запити ping. Я думаю, що деякі постачальники не дозволяють запити ping. Наприклад, я тестував планшет Samsung 10.1 (4.3), і рішення не працює. Коли я запускаю команду ping через утиліту командного рядка, я отримую помилку дозволу. Команда також не працює на емуляторах. Будьте обережні, використовуючи це рішення.
Ерен Йілмаз

9
Такий підхід працює не на всіх телефонах. Це виходить з ладу, наприклад, у Samsung Galaxy S3. Дивіться тут: Чому ping працює на деяких пристроях, а не на інших?
Аділь Хуссей

1032

Якщо пристрій у режимі літака (або, мабуть, в інших ситуаціях, коли немає доступної мережі), 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:

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

Ще одна невелика точка, якщо вам абсолютно потрібне підключення до мережі в даний момент часу, то, можливо, краще використовувати netInfo.isConnected(), ніж ніж netInfo.isConnectedOrConnecting. Я думаю, це залежить від індивідуального використання.


109
imo, вам все одно слід і потрібно перевірити, чи немає винятків http timeout, оскільки можуть бути ситуації, коли мережа підключена, але фактичного підключення до Інтернету не було б, оскільки єдиний спосіб отримати доступ до неї, наприклад, через VPN - таким чином, у вас є, для наприклад, WI-FI-з'єднання, але фактичного інтернет-трафіку немає. Інша ситуація - підключення до сервера. Це два питання, які я нещодавно запускав, і менеджер з’єднань не допоможе там.
опівночі

21
Я погоджуюсь з опівночі та Пінту, ця відповідь не повинна бути прийнятою відповіддю, вона не має нічого спільного з перевіркою того, що ти знаходишся в Інтернеті. Наприклад, якщо телефон підключений до мережі WiFi з порталом, що перебуває в полоні, наприклад, в готелі, ця функція буде неправильно повернути справжнє значення. Правильна відповідь - пінг-сервер у загальнодоступному Інтернеті.
Мігель

9
коли для мого роутера немає робочого Інтернету, якщо я підключуюся до маршрутизатора через wifi, то наведений вище код повертає справжнє значення. Але, це не повинно бути, правда? Чи можете ви мені допомогти
MoHaN K RaJ

5
Мені довелося додати Контекст, context.getSystemServiceабо він не працює. Тут я зрозумів androidhive.info/2012/07/…
Франциско Корралес Моралес

1
Хороший спосіб перевірити наявність мережі. Але як перевірити доступ до Інтернету?
Тамас Болварі

296

Не потрібно бути складним. Найпростіший і базовий спосіб - це використовувати ACCESS_NETWORK_STATEдозвіл і просто зробити підключений метод

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

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

Ви також можете використовувати, requestRouteToHostякщо у вас є на увазі конкретний хост і тип з'єднання (wifi / mobile).

Вам також знадобляться:

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

у вашому Android-маніфесті.


82
краще зробити нульову перевірку на рівні cm.getActiveNetworkInfo (), вона кинула нуль, якщо активна мережа не була доступною.
Самуїл

см stackoverflow.com/a/11691676/1979773 для більш глибокого exaplanation про requestRouteToHost ()
Spartako

Мені довелося додати Контекст, context.getSystemServiceабо він не працює. Тут я зрозумів androidhive.info/2012/07/…
Франциско Корралес Моралес

9
Це рішення повернеться істинним, якщо ви підключені до точки доступу WiFi, навіть якщо ця точка доступу НЕ має підключення до Інтернету.
Джош


63

Щоб приступити getActiveNetworkInfo()до роботи, потрібно додати до маніфесту наступне.

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

Це, безумовно, має правильну відповідь (витрачається занадто багато часу, щоб з'ясувати, що, чорт, не так).
Індрек Кюе

2
Дозвіл INTERNET для цього НЕ потрібен, просто ACCESS_NETWORK_STATE. INTERNET потрібен лише у тому випадку, якщо ви фактично встановлюєте з'єднання з віддаленими місцями, не запитуючи про стан радіопристрою пристрою.
Том

3
На сьогодні ваша відповідь насправді не відповідь, це лише відносно незначне доповнення до інших відповідей. Якби всіх інших відповідей тут не було, чи мала би ваша відповідь? Не зовсім. Тому що якщо це краще, розгорніть свою відповідь кодом про те, як її використовувати, або видаліть свою відповідь та додайте інформацію в іншу відповідь (ви не втратите жодної репутації)
Тим

Будьте уважні, getActiveNetworkInfo()це застаріле в рівні API 29
Переповнення стека

46

Погляньте на клас ConnectivityManager. Ви можете використовувати цей клас для отримання інформації про активні з'єднання хоста. http://developer.android.com/reference/android/net/ConnectivityManager.html

EDIT: Ви можете використовувати

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

або

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

і проаналізувати перераховану кількість деталей повернутого об'єкта NetworkInfo

EDIT EDIT: Щоб дізнатися, чи можете ви отримати доступ до хоста, ви можете використовувати

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

Очевидно, я використовую Context.getSystemService (Context.CONNECTIVITY_SERVICE) як проксі, щоб сказати

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

Не впевнений, але це здається кодом, щоб перевірити, яке саме мережеве з'єднання зараз увімкнено. Наприклад, на WiFi, немає гарантії, що ваш домашній wifi-роутер підключений до Internett ... щоб перевірити, чи потрібно насправді робити запит на інтернет-сервер ...
сервера

1
У розділі EDIT EDIT сталася помилка, я вийшов із запиту requestRouteToHost (). Перечитайте відповідь зараз :)
Chinmay Kanchi

requestRouteToHost застарілий.
Ягазіель

46

перевірити цей код ... він працював на мене :)

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

3
Що Google не працює? Для цього також потрібен дозвіл INTERNET, що не є необхідним для даного завдання. Нарешті, це споживає дані (навіть якщо вони незначні). Це просто здається такою хитрості.
Том

28
@Якщо чесно, це, мабуть, єдина правильна відповідь. Інші приклади показують тільки , якщо мережеве з'єднання є і / або , якщо є підключення до цієї мережі, але не дає відповіді на питання , якщо ця мережа фактично може також зробити віддалене з'єднання (наприклад , на веб - сайт). Отже, це відповідає на афіші Q, а інші відповіді не відповідають
slinden77

2
@dmmh Так, це, на жаль, вірно з того, що я бачив з Android API. Може бути, просто пінг може бути краще, stackoverflow.com/questions/3905358 / ... . Якщо ви насправді заклопотані, ви можете навіть включити список IP-адрес до ping, оскільки, хоча є дуже маленький шанс, що Google коли-небудь знизиться, є ще менший шанс, що Google, Bing і Yahoo будуть в той же день знищені . Просто мої думки.
Том

10
Немає сенсу робити цю перевірку. Якщо ви збираєтеся витратити системний час та мережеві ресурси для підключення до Google, ви могли б витратити їх замість того, щоб підключитися до ресурсу, який вам насправді важливий.
Бенджамін

16
У Китаї Google заблокували !!
Антон

26

Знайдено та змінено (!) За цим посиланням :

У свій файл маніфесту додайте щонайменше:

<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;
    }
}

18

Я зробив цей код, він найпростіший і це просто булевий. запитуючиif(isOnline()){

Ви отримуєте, якщо є з'єднання і якщо він може підключити до сторінки код статусу 200 (стабільне з'єднання).

Обов’язково додайте правильні INTERNETта ACCESS_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;
}

6
Можливо, вам слід замінити 200 на HttpURLConnection.HTTP_OK
Yash,

5
Що робити, якщо Google не працює?
Yauraw Gadav

12

Це працює для мене:

Щоб перевірити наявність мережі:

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;
}

це прекрасне рішення, щоб перевірити, чи працює сервер, працює дуже добре. Дякую!
Віллі

1
isOnline () взагалі не повинен працювати на основному потоці, ніби є сигнал Wi-Fi, але немає Інтернету, це займе занадто довго і блокує основний потік.
гумав

9

Існує більше ніж один спосіб

По-перше, найкоротший, але неефективний шлях

Потрібно лише дозвіл на стан мережі

<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- це рішення, я тільки що додав його в метод, це спрощений метод всієї експлуатації
ConnectivityManager повертає істину, якщо є мережевий доступ, а не доступ до Інтернету, тобто якщо ваш WiFi підключений до роутера, але у маршрутизатора немає Інтернету повертає вірно, перевіряє наявність з'єднання

По-друге, ефективний спосіб

Потрібні дозволи мережі та Інтернет

<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, інакше він може кинутись android.os.NetworkOnMainThreadExceptionу деяких випадках

  • ConnectivityManager використовується для перевірки доступу до мережі, якщо істина надсилає запит (Ping)

  • Запит на надсилання http://clients3.google.com/generate_204: Ця відома URL-адреса, як відомо, повертає порожню сторінку зі статусом HTTP 204, це швидше і ефективніше, ніж http://www.google.comпрочитайте це . якщо у вас є веб-сайт, його краще розміщувати замість google, лише якщо ви використовуєте його в додатку

  • Час очікування може бути змінено (20 мс -> 2000 мс), зазвичай використовується 1500 мс


2
Велике запитання, на жаль, у вас немає більше балів. Це має бути правильна відповідь.
Jhon Fredy Trujillo Ortega

Я новачок в android. Хоча ця відповідь є добре висвітленою, і вона привертає більше уваги @ 7569106
Mazen Embaby

1
найкраща та повна відповідь, дякую. якщо хтось має веб-сайт, помітить, що ця умова повинна сподобатися цьому urlc.getResponseCode () == 200 і не потрібно перевіряти urlc.getContentLength () == 0
AREF

ваш другий варіант отримати аварію, я не знаю, чому
nafees ahmed

це заморожує додаток
nafees ahmed

8

З усього, що я бачив поки що, найкоротшим і чистішим способом має бути:

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: Це не пінг жодного хоста, він просто перевіряєстату підключення, тому якщо у вашого маршрутизатора немає підключення до Інтернету, а ваш пристрій підключений до нього, цей метод повернеться правдою, хоча у вас немає Інтернету.
Для фактичного тестування я рекомендую виконати запит HttpHead (наприклад, на www.google.com) і перевірити стан, якщо з його 200 ОК все нормально, а ваш пристрій має підключення до Інтернету.


Я хотів поставити цей метод у глобальний клас, тому мені довелося використовувати цю версію, щоб я міг передати контекст із тієї діяльності, з якої я йому дзвонив. Дякую!
RyanG

8

Ось метод, який я використовую:

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


7

Один важливий випадок використання мобільних пристроїв для забезпечення фактичного з'єднання. Це поширена проблема, коли користувач мобільного зв'язку входить у мережу Wi-Fi з "Портативним порталом", в якому їм потрібно увійти. Я використовую цю функцію блокування у фоновому режимі, щоб переконатися, що з'єднання існує.

/*
 * 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;
}

3
+1 для фактичної перевірки підключення до кінця. Однак у ситуації з "Порталом полонених" я виявив, що багато хто пройде вищевказаний тест, навіть якщо ви не ввійшли - ви отримаєте сторінку входу та відповідь 200, незалежно від того, яку URL-адресу ви запитуєте. Тому я намагаюся потрапити на сторінку в своєму власному домені, який я знаю, що не існує, і переконайтеся, що я отримав 404. По черзі ви можете перейти на відому існуючу сторінку, переконайтеся, що ви отримаєте 200, і перевірте вміст, який повертається, щоб переконатися, що це те, чого ви очікуєте.
GreyBeardedGeek

6

Ви можете переглядати всі підключення до мережі та перевірити, чи є принаймні одне доступне з'єднання:

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;
}

6

Для мене було недоброю практикою перевіряти стан з'єднання в класі активності, оскільки

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

слід викликати там або вам потрібно натиснути свій екземпляр діяльності (контекст) на клас обробника з'єднання, щоб мати можливість перевірити стан з'єднання там. Якщо немає доступного з'єднання (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)


6

Це працює для мене. Спробуй.

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());
}}

Ця відповідь зараз не може працювати, оскільки ми не можемо отримати доступ до мережі на головній потоці зараз.
正宗 白 布鞋

1
Я маю на увазі з API рівня 11, це не працює. Причина: developer.android.com/reference/android/os/… . Якщо він працює для вас, це означає, що ви запускаєте цей код на старому пристрої Android. (до ГБ).
正宗 白 布鞋

StrictMode.ThreadPolicy Policy = новий StrictMode.ThreadPolicy.Builder () .permitAll (). Build (); StrictMode.setThreadPolicy (політика); додайте в ці два рядки два ваші програми, щоб уникнути виключення з головної мережі в мережі
selva_pollachi

Гаразд, я не повинен говорити, що це не може працювати, я можу сказати, що він може працювати (за старою цільовою версією або встановленням Strictmode), але це не рекомендується. Це може спричинити ANR легко. (З такою великою конфігурацією тайм-ауту в httpurlconnection)
正宗 白 布鞋

ви маєте рацію .. просто я це ставлю, тому що це теж один із способів.
selva_pollachi

6

Цей метод дає вам можливість дійсно швидкого методу (для зворотного зв’язку в режимі реального часу) або більш повільного методу (для разових перевірок, які вимагають надійності)

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;
}

5

Я використовую цей код замість 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();
    }

Було б чудово, якби ви уточнили, чи означає IOException відсутність підключення до Інтернету та наскільки він може бути надійним.
Мілад.Нозарі

5

Перевірити стан підключення до мережі Інтернет та Інтернету не складно. Клас нижче 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;
        }
    }
}

Для отримання більш детальної інформації див. Як перевірити стан мережі Інтернет / Інтернет


5

Найкращий підхід:

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

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

1
Мені подобається такий підхід, але я повинен зазначити деякі речі. isReachable () повертає булеву форму, тому замість повернення true у розділі спробу ви можете зробити це як boolean linked = InetAddress.getByName ("google.com"). isReachable (3); потім поверніться підключеним. Крім того, IsReacheable викидає винятки IOException та IllegalArgumentException, тому буде хорошою ідеєю замінити UnknownHostException на IllegalArgumentException і включити третій catch: catch (виняток E).
Яш

2
Але тоді, IsReachable використовує ICMP, який може вимагати привілеїв root та використовує порт 7, який зазвичай не має запущених служб в останніх системах. Тому найкращий спосіб перевірити маршрут до онлайн-сервісу - регулярний TCP; отже, голос "вниз".
Яш

5

Далі йде код з мого Utilsкласу:

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

5
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();
}

}

Як і всі інші, хто не прочитав проблему, це не вирішує проблему, оскільки воно не перевіряє наявність з'єднання з Інтернетом. Підключення до локальної точки доступу до wifi повернеться справжнім, навіть якщо точка доступу не дозволить вам перейти в Інтернет.
Педро Помбейро

5

Ви можете використовувати цей метод для виявлення доступності мережі-

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;
    }

5

Я застосував рішення, яке надає @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
}

4

Це висвітлено в документах для Android http://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html


1
Але описаний там метод насправді не перевіряє наявність підключення до Інтернету, він просто перевіряє, чи встановлено зв’язок (чи є доступ до Інтернету чи ні). Назва цього офіційного доктора справді вводить в оману.
Тіаго

2
Дати відповідь на питання краще, ніж просто розмістити посилання на інформацію. Що робити, якщо посилання загине? У нас не буде відповіді.
Хосе Льоусас

4

Я переглянув усі відповіді, і я придумав власну відповідь, яка спочатку перевіряє, чи є Інтернет, і чи є Інтернет, а потім перевіряє, чи активний він чи ні.

Я включив усі необхідні методи та класи, щоб перевірити наявність активного підключення до Інтернету.

NetworkUtils.class

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();
    }
}

Ви можете перевірити, чи Інтернет активний, використовуючи наведений нижче код:

 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);
            }
        });
    }

Краще нанизування пакетів у ваших NetworkUtils, а отже, "змушуйте" розробника не помилятися на використанні вашого методу
Ewoks

Щоб видалити одну зайву, якщо це умова. if ((NetworkUtils.isInternetActiveWithPing () == NetworkUtils.STATUS_CONNECTED) || NetworkUtils.isInternetActiveWithInetAddress ()) {// Робіть мережеві операції} else {// Повідомлення про помилку}
Jawad

4

Дуже важливо перевірити, чи є у нас зв’язок із 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" />

Приємний підсумок компонентів для підключення пристрою, просто потрібно обернути їх у випробуваннях / захоплення, щоб уникнути збоїв. Точно так само виконайте свої звичайні HttpURLConnection дзвінки, доки вони зафіксовані в обробці помилок, ви незабаром дізнаєтесь, чи є у вас підключення до Інтернету
rangi

4

Котлін та корутини

Я помістив функцію в a ViewModel, яке має viewModelScope. Використовуючи спостережуваний, LiveDataя інформую активність про з'єднання.

ViewModel

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

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

                    withContext(Dispatchers.Main) {
                        _connection.value = true
                    }
                }
                catch(ex: IOException) {
                    withContext(Main) {
                        _connection.value = 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
         }
     }
  }

3

Просто створіть такий клас, який перевіряє наявність підключення до Інтернету:

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;
    }
}

Цей клас просто містить метод, який повертає булеве значення стану з'єднання. Тому, простіше кажучи, якщо метод знаходить дійсне підключення до Інтернету, повернене значення має 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.");
        }
    }

У наведеному вище коді, якщо результат хибний, (отже, немає підключення до Інтернету, користувач переходить на панель wi-fi Android, де йому пропонується підключитися до точки доступу до wi-fi.


3

Оновлення 29/06/2015 Якщо ви використовуєте Xamarin.Android і хочете перевірити наявність підключення, ви можете використовувати пакет Nuget, який би надав вам цю функціональність на кількох платформах. Хороші кандидати тут і тут . [Кінець оновлення]

Наведені вище відповіді досить хороші, але всі вони є на Яві, і майже всі вони перевіряють на зв’язок. У моєму випадку мені потрібно було мати зв’язок із певним типом зв’язку, і я розвиваюся на Xamarin.Android. Більше того, я не передаю посилання на свою діяльність "Контекст" на рівні апаратного забезпечення, я використовую "Контекст програми". Тож ось моє рішення, на випадок, якщо хтось приїде сюди з подібними вимогами. Я не пройшов повне тестування, але відповідь оновлю, як тільки я закінчу тестування

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
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.