从MongoDB获取数据并执行聚合查询时应用崩溃求助
问题描述
尝试从MongoDB获取数据并执行聚合查询,点击按钮后应用崩溃,错误日志及代码如下,求问题原因及解决方案。
错误日志
2023-12-17 17:10:57.338 1082-1715 OneSearchS...stProvider com...le.android.apps.nexuslauncher E Failed to fetch suggestions from AppSearch, fallback to AGA java.util.concurrent.CompletionException: java.util.NoSuchElementException: No value present at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:308) at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:323) at java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:684) at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:486) at java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2138) at com.google.android.apps.nexuslauncher.allapps.H0.onResult(Unknown Source:59) at android.app.appsearch.SearchSessionUtil$1.lambda$onResult$0(SearchSessionUtil.java:129) atandroid.app.appsearch.SearchSessionUtil$1.$r8$lambda$_nlk9WiPjSfaAsqKYmp0aPvSRC0(SearchSessionUtil.java:1) atandroid.app.appsearch.SearchSessionUtil$1$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:13) at android.os.Handler.handleCallback(Handler.java:958) atandroid.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:205) at android.os.Looper.loop(Looper.java:294) at android.os.HandlerThread.run(HandlerThread.java:67) Caused by: java.util.NoSuchElementException: No value present at java.util.Optional.get(Optional.java:144) at com.google.android.apps.nexuslauncher.allapps.H0.onResult(Unknown Source:16) at android.app.appsearch.SearchSessionUtil$1.lambda$onResult$0(SearchSessionUtil.java:129) at android.app.appsearch.SearchSessionUtil$1.$r8$lambda$_nlk9WiPjSfaAsqKYmp0aPvSRC0(SearchSessionUtil.java:1) at android.app.appsearch.SearchSessionUtil$1$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:13) at android.os.Handler.handleCallback(Handler.java:958) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loopOnce(Looper.java:205) at android.os.Looper.loop(Looper.java:294) at android.os.HandlerThread.run(HandlerThread.java:67)
相关代码
获取MongoClient代码
@SuppressLint("AuthLeak") fun getMongoClient(): MongoClient { return MongoClients.create("My String goes here -> taken from mongodb") }
从MongoDB获取数据代码
fun fetchDataFromMongoDB(collection: MongoCollection<Document>): List<Document> { // Define your aggregation pipeline stages here val pipeline = listOf( Aggregates.match(Filters.eq("age", "20")), // Add more pipeline stages as needed ) // Execute the aggregation pipeline val result = collection.aggregate(pipeline) // Convert the result to a list of documents val documents = mutableListOf<Document>() try { // Code that might be causing the exception result.forEach { document -> documents.add(document) println("Pinged your deployment. You successfully connected to MongoDB!") } } catch (e: Exception) { e.printStackTrace() } return documents }
主界面代码
@Composable fun MainMongoData() { var fetchedData by remember { mutableStateOf("") } Column { // Display your fetched data in a TextField TextField( value = fetchedData, onValueChange = { /* No-op for read-only TextField */ }, label = { Text("Fetched Data") }, readOnly = true, modifier = Modifier.fillMaxWidth() ) // Button to trigger search Button(onClick = { val client = getMongoClient() val database = client.getDatabase("people") val collection = database.getCollection("person") val documents = fetchDataFromMongoDB(collection) // Concatenate document JSON strings and update the TextField fetchedData = documents.joinToString("\n") { it.toJson() } client.close() }) { Text("Search") } } }
问题原因及解决方案
1. 错误日志的误导性
日志中显示的崩溃来自系统启动器的AppSearch模块,和你的MongoDB代码无关。实际崩溃是因为代码中存在未正确处理的异常,未在日志中完整输出。
2. 核心问题:主线程执行网络操作
MongoDB请求在Compose按钮的点击回调中直接执行,属于主线程上的远程数据库操作,Android会抛出NetworkOnMainThreadException导致崩溃,而现有代码的try-catch未有效拦截该异常。
3. 聚合查询的潜在问题
Filters.eq("age", "20")如果数据库中age是数字类型,字符串匹配会查不到数据,但不会直接崩溃;- 聚合查询返回的游标未手动关闭,可能导致资源泄漏。
解决方案
(1)切换到后台线程执行数据库操作
使用协程将数据库操作放到IO线程,更新UI时切回主线程:
@Composable fun MainMongoData() { var fetchedData by remember { mutableStateOf("") } val scope = rememberCoroutineScope() Column { TextField( value = fetchedData, onValueChange = {}, label = { Text("Fetched Data") }, readOnly = true, modifier = Modifier.fillMaxWidth() ) Button(onClick = { scope.launch(Dispatchers.IO) { var client: MongoClient? = null try { client = getMongoClient() val database = client.getDatabase("people") val collection = database.getCollection("person") val documents = fetchDataFromMongoDB(collection) withContext(Dispatchers.Main) { fetchedData = documents.joinToString("\n") { it.toJson() } } } catch (e: Exception) { e.printStackTrace() withContext(Dispatchers.Main) { fetchedData = "请求失败: ${e.message}" } } finally { client?.close() } } }) { Text("Search") } } }
(2)完善数据获取逻辑与异常处理
确保游标安全遍历并手动关闭,同时修正age的匹配类型:
fun fetchDataFromMongoDB(collection: MongoCollection<Document>): List<Document> { val pipeline = listOf( Aggregates.match(Filters.eq("age", 20)) // 若age为数字类型,用20而非"20" ) val documents = mutableListOf<Document>() var cursor: MongoCursor<Document>? = null try { cursor = collection.aggregate(pipeline).iterator() while (cursor.hasNext()) { documents.add(cursor.next()) } } catch (e: Exception) { e.printStackTrace() } finally { cursor?.close() } return documents }
(3)配置必要权限与连接信息
在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
同时确认MongoDB连接字符串包含正确的用户名、密码、集群地址等信息。
内容的提问来源于stack exchange,提问作者Josef M
相关产品推荐
相关产品推荐

