1. ホーム
  2. java

[解決済み] Androidでインターネット接続を確認するには?InetAddressがタイムアウトしない

2022-03-14 12:52:33

質問

を取得しました。 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();
    }   
}

解決方法は?

ネットワーク接続/インターネット接続

  • isConnectedOrConnecting() (ほとんどの回答で使われています) は ネットワーク 接続
  • それらのネットワークのいずれかが インターネット にアクセスするには、次のいずれかを使用します。

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) インターネット上のソケットに接続する(上級編)

// 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スレッドで実行できない

これは、あらゆるデバイスで非常に確実に動作し、非常に高速です。しかし、別のタスクで実行する必要があります (例. ScheduledExecutorService または AsyncTask ).

想定される質問

  • 本当に速度は十分ですか?

    はい、とても速いです;-)

  • インターネットを確認するには、インターネットで何かをテストする以外に確実な方法はないのでしょうか?

    私の知る限りではありませんが、教えていただければ、回答を編集します。

  • DNSがダウンしている場合は?

    Google DNS(例. 8.8.8.8 )は、世界最大のパブリックDNSです。2018年現在、1日1兆件以上のクエリを処理している [... 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コルーチン、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 */ });