Java 在不阻塞主线程的情况下检索HTTP响应
我目前正在将一个用Objective-C编写的网络库移植到Java,我需要向服务器发出异步HTTP请求的功能,而不依赖任何第三方库(因此,没有Apache依赖项)。我正在使用Java 在不阻塞主线程的情况下检索HTTP响应,java,android,multithreading,concurrency,nonblocking,Java,Android,Multithreading,Concurrency,Nonblocking,我目前正在将一个用Objective-C编写的网络库移植到Java,我需要向服务器发出异步HTTP请求的功能,而不依赖任何第三方库(因此,没有Apache依赖项)。我正在使用HTTPUrlConnection来实现这一点;但是,正如您所知,这是一个同步过程 我试图使用ExecutorService和Future结构将并发性实现到这个流程中。我需要使用Callable而不是Runnable,因为我需要处理服务器返回给我的响应消息。以下是我所做工作的一个小概述: ExecutorService ex
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):
- 我不想依赖第三方库,除非这是绝对必要的
- 我不能使用
,因为我希望我的最低API级别为16CompletableFuture
- 我不想在Android端使用
处理这种并发性,因为最初,这是在网络库中使用AsyncTasks
(Objective-C)处理的CompletionHandler
有没有一种方法可以在不阻塞的情况下使用
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处理程序上发布帖子。请阅读。你的问题很长,大多数人在这个网站上都会放弃阅读。非常感谢你,我会尝试一下!谢谢你,我现在就去试一试!