我有一个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();
    }   
}

推荐答案

Network connection / Internet access

  • isConnectedOrConnecting()(在大多数答案中使用)判断任何network连接
  • 要知道这些网络是否有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上的插座(高级)

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

+速度非常快(无论采用哪种方式),可在所有设备上运行,very可靠

-无法在UI线程上运行

这在每一台设备上都能非常可靠地工作,而且速度非常快.不过,它需要在单独的任务中运行(例如,ScheduledExecutorServiceAsyncTask).

可能的问题

  • 它真的够快吗?

    Yes, very fast ;-)

  • 除了在网上测试之外,有没有可靠的方式来判断互联网?

    Not as far as I know, but let me know, and I will edit my answer.

  • 如果DNS关闭了怎么办?

    Google DNS (e.g. 101) is the largest public DNS in the world. As of 2018 it handled over a trillion queries a day [100]. Let 's just say, your app would probably not be the talk of the day.

  • 需要哪些权限?

    <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?)

 

Extra: One-shot RxJava/RxAndroid Example (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 */}

Extra: One-shot RxJava/RxAndroid Example (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 {

        }
    });

Extra: One-shot AsyncTask Example

Caution:这显示了另一个如何处理请求的示例.然而,由于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 */ });

Java相关问答推荐

如果您仅同步写操作,Java布尔线程是否安全

在没有maven或IDE的情况下从命令行运行PFA模块化应用程序时出现神秘错误

Java中Stream(java.util.stream)和linkedList数据 struct 之间是什么关系?

如何为具有多对多关系的实体的给定SQL查询构建JPA规范?

如果给定层次 struct 级别,如何从其预序穿越构造n元树

如何使用解析器组合子解析Java数组类型签名?

AlarmManager没有在正确的时间发送alert

Java中后期绑定的替代概念

具有多种令牌类型和段的复杂Java 17正则表达式

Spring Boot Maven包

相同的Java SerializedLambda为implMethodKind返回不同的结果

为什么Java编译器不区分不同类型的方法?

try 判断可选参数是否为空时出现空类型安全警告

格式中的特定回录键-值对

支持MySQL 5.6的最新Hibernate版本

我可以在@Cacheable中使用枚举吗

组合连接以从两个表返回数据

从12小时开始的日期模式

如何使用Java对随机生成的字母数字优惠券代码进行过期设置

根据应用程序 Select 的语言检索数据