Java 在不阻塞主线程的情况下检索HTTP响应

Java 在不阻塞主线程的情况下检索HTTP响应,java,android,multithreading,concurrency,nonblocking,Java,Android,Multithreading,Concurrency,Nonblocking,我目前正在将一个用Objective-C编写的网络库移植到Java,我需要向服务器发出异步HTTP请求的功能,而不依赖任何第三方库(因此,没有Apache依赖项)。我正在使用HTTPUrlConnection来实现这一点;但是,正如您所知,这是一个同步过程 我试图使用ExecutorService和Future结构将并发性实现到这个流程中。我需要使用Callable而不是Runnable,因为我需要处理服务器返回给我的响应消息。以下是我所做工作的一个小概述: ExecutorService ex

我目前正在将一个用Objective-C编写的网络库移植到Java,我需要向服务器发出异步HTTP请求的功能,而不依赖任何第三方库(因此,没有Apache依赖项)。我正在使用
HTTPUrlConnection
来实现这一点;但是,正如您所知,这是一个同步过程

我试图使用
ExecutorService
Future
结构将并发性实现到这个流程中。我需要使用
Callable
而不是
Runnable
,因为我需要处理服务器返回给我的响应消息。以下是我所做工作的一个小概述:

ExecutorService executorService = Executors.newSingleThreadExecutor();
  Future<String> future = executorService.submit(new Callable<String>() {
     @Override
     public String call() throws Exception {
        return postRequest(reqMsg);
     }
  });
ExecutorService ExecutorService=Executors.newSingleThreadExecutor();
Future=executorService.submit(new Callable()){
@凌驾
公共字符串调用()引发异常{
返回请求(reqMsg);
}
});
其中reqMsg是请求消息(XML),postRequest方法以字符串形式返回响应消息(也是XML格式)。现在,为了检索这个可调用任务的返回值,我需要使用
future.get()
。但是,这个方法是一个阻塞调用,这意味着它会阻塞主线程,直到有响应可用为止。这不是我想要的

我正在将一个iOS应用程序移植到Android,我将使用J2ObjC在这些平台之间建立一个跨平台的共享库。在iOS版本(即库的Obj-C版本)中,有处理HTTP请求结果的完成处理程序,并且是异步进行的。不幸的是,Java在Java8中引入了这种回调方式来处理它,并且具有CompletableFuture。然而,Android只支持从API级别24开始的CompletableFuture。我希望能够支持回到Jelly Bean(API 16)的API级别。据我所知,“为了使JAR文件与Android兼容,它只能引用作为Android的一部分可用的类和其他专门在JAR中实现的类”。您可以建议使用异步任务;但是,我希望在Java网络端处理HTTP请求的并发性,因为这个库很可能在两个平台上共享

我尝试过显式地使用线程;然而,当我研究它时,我发现为了使用Callables,您需要使用ExecutorService和Future(另外,显式创建线程似乎会带来一些性能开销,尽管我认为<1000ms的开销是可以接受的)。再次重申(即TL:DR):

  • 我不想依赖第三方库,除非这是绝对必要的

  • 我不能使用
    CompletableFuture
    ,因为我希望我的最低API级别为16

  • 我不想在Android端使用
    AsyncTasks
    处理这种并发性,因为最初,这是在网络库中使用
    CompletionHandler
    (Objective-C)处理的


有没有一种方法可以在不阻塞的情况下使用
Future.get()
?(一个善意的提醒,while循环检查
Future.isDone()
也会阻塞主线程)。

你的问题没有多大意义。一方面,您希望在单独的线程中获取数据,但同时在另一个线程中获取数据,而无需等待获取线程完成

您需要做的是将fetch和“对获取的数据做任何事情”包装成Runnable,并在单独的线程中运行它

确保在事件分派线程中更新UI,以防需要使用获取的数据更新它。

调用
Future.get()
是一个阻塞操作,您无法更改它

你想在这里得到的是一个回调一旦工作完成。为此,您根本不必使用
未来
。您可以始终使用
Executor.execute()
Runnable
执行与
可调用的
完全相同的操作,但它不应返回值,而应使用该值调用方法参数-callback中提供的自定义值。基本上相当于Java 8中引入的
消费者
接口

ExecutorService executorService = Executors.newSingleThreadExecutor();

public void execute(YourRequestObject reqMsg, Consumer<String> consumer) {
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            String result = postRequest(reqMsg);
            consumer.accept(result);
        }
    });
}
ExecutorService ExecutorService=Executors.newSingleThreadExecutor();
public void execute(YourRequestObject reqMsg,使用者){
executorService.execute(新的Runnable(){
@凌驾
公开募捐{
字符串结果=postRequest(reqMsg);
消费者接受(结果);
}
});
}
也不要每次都创建executor。只需为所有操作使用一个执行器。可能是缓存的而不是单线程的


请记住,您的回调将在executor线程上调用。如果您想更新UI,需要在UI处理程序上发布帖子。

请阅读。你的问题很长,大多数人在这个网站上都会放弃阅读。非常感谢你,我会尝试一下!谢谢你,我现在就去试一试!