我得到了一个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();
    }   
}

当前回答

非常重要的是检查我们是否与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" />

其他回答

检查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网络/ Internet连接状态

这在android文档中有涉及 http://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html

网络连接/互联网接入

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线程上运行

这工作非常可靠,在每个设备上,非常快。它需要在一个单独的任务中运行(例如ScheduledExecutorService或AsyncTask)。

可能的问题

Is it really fast enough? Yes, very fast ;-) Is there no reliable way to check internet, other than testing something on the internet? Not as far as I know, but let me know, and I will edit my answer. What if the DNS is down? Google DNS (e.g. 8.8.8.8) is the largest public DNS in the world. As of 2018 it handled over a trillion queries a day [1]. Let 's just say, your app would probably not be the talk of the day. Which permissions are required? <uses-permission android:name="android.permission.INTERNET" /> Just internet access - surprise ^^ (Btw have you ever thought about, how some of the methods suggested here could even have a remote glue about internet access, without this permission?)

 

额外:一次性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 */ });

我已经尝试了近5+不同的android方法,发现这是谷歌提供的最佳解决方案,特别是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);
  }

它比任何其他可用的解决方案都更快、高效和准确。

正如Android文档建议的那样,之后

getActiveNetworkInfo()在Android 10中已弃用。使用 而不是针对Android 10 (API级别)的应用程序的NetworkCallbacks 29)更高。

下面是我们目前检查网络连接的方法:

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