Java类从MongoDB取数完成后返回Android主程序的实现问询
嘿,我看你现在卡在MongoDB异步查询没法同步返回结果的问题上了对吧?你的代码里用了continueWith异步回调,但原方法要返回Document[],直接这么写肯定拿不到正确结果——因为异步任务还没完成,方法就已经返回了。下面给你几个实用的解决方案,你可以根据自己的Android场景来选:
方案一:使用Task.await()同步等待结果
MongoDB的Java驱动里,find()返回的Task对象提供了await()方法,可以阻塞当前线程直到异步任务完成,这样就能拿到结果再返回。修改后的代码如下:
public Document[] search(Document query, String databaseName, String collectionName) { Log.i(TAG, "Search query: " + query); try { // 阻塞线程,等待异步查询完成 List<Document> resultList = _mongoClient.getDatabase(databaseName) .getCollection(collectionName) .find(query) .await(); // 将List转换为Document数组返回 return resultList.toArray(new Document[0]); } catch (ExecutionException | InterruptedException e) { Log.e(TAG, "查询执行失败", e); // 这里可以返回null,或者抛出自定义业务异常,根据你的需求调整 return null; } }
⚠️ 重要提醒:这个方法绝对不能在Android的主线程(UI线程)调用!因为await()会阻塞线程,主线程阻塞超过5秒就会触发ANR(应用无响应)。如果要从UI层调用这个方法,一定要把它放到子线程里执行,比如用ExecutorService、AsyncTask或者Kotlin协程的后台调度器。
方案二:改用回调接口(适合UI交互场景)
如果你的查询是从UI线程触发的,或者不想阻塞线程,那用回调接口是更稳妥的选择。我们可以定义一个回调接口,让异步任务完成后主动通知调用者:
首先定义回调接口:
public interface SearchCallback { // 查询成功时回调,返回结果数组 void onSuccess(Document[] result); // 查询失败时回调,返回异常信息 void onFailure(Exception e); }
然后修改search方法,去掉返回值,改为接受回调参数:
public void search(Document query, String databaseName, String collectionName, SearchCallback callback) { Log.i(TAG, "Search query: " + query); _mongoClient.getDatabase(databaseName) .getCollection(collectionName) .find(query) .continueWith(task -> { if (task.isSuccessful()) { List<Document> resultList = task.getResult(); Document[] resultArray = resultList.toArray(new Document[0]); // 通知调用者查询成功 callback.onSuccess(resultArray); } else { // 通知调用者查询失败 callback.onFailure(task.getException()); } return null; }); }
调用的时候就可以这样写:
// 假设在Activity里调用 search(query, "your_db_name", "your_coll_name", new SearchCallback() { @Override public void onSuccess(Document[] result) { // 查询成功后,回到主线程更新UI runOnUiThread(() -> { // 这里写更新UI的逻辑,比如展示查询结果 }); } @Override public void onFailure(Exception e) { Log.e(TAG, "查询失败", e); // 这里处理错误,比如弹提示给用户 } });
这个方案的优势是不会阻塞线程,完美适配Android的UI线程规则,查询完成后可以安全地更新UI。
方案三:使用Kotlin协程(如果项目支持Kotlin)
如果你的Android项目已经用了Kotlin,那协程是处理异步任务最优雅的方式——既能保持同步代码的可读性,又不会阻塞线程。你可以这样写:
// 定义挂起函数,只能在协程或其他挂起函数里调用 suspend fun search(query: Document, databaseName: String, collectionName: String): Array<Document>? { Log.i(TAG, "Search query: $query") return try { val resultList = _mongoClient.getDatabase(databaseName) .getCollection(collectionName) .find(query) .await() resultList.toTypedArray() } catch (e: Exception) { Log.e(TAG, "查询失败", e) null } }
调用的时候,在协程作用域里执行:
// 比如在Activity里用lifecycleScope(需要依赖androidx.lifecycle:lifecycle-runtime-ktx) lifecycleScope.launch { val result = search(query, "your_db_name", "your_coll_name") // 这里已经在主线程了,可以直接更新UI if (result != null) { // 处理查询结果 } else { // 处理错误 } }
协程的方式既避免了回调嵌套,又符合Android的线程规则,是现在推荐的异步处理方式。
内容的提问来源于stack exchange,提问作者Ruben

