Android 12 AppSearch开发中Futures引用缺失问题及依赖导入、Kotlin协程替代方案咨询
解决AppSearch中Futures引用问题与协程替代方案
一、修复Futures和FutureCallback的依赖问题
你遇到的Futures和FutureCallback引用未知的问题,核心是缺少对应的基础依赖包。在现有依赖配置中添加以下内容即可解决:
implementation "androidx.concurrent:concurrent-futures:1.1.0"
同时要确保代码中导入正确的类:
import androidx.concurrent.futures.Futures import androidx.concurrent.futures.FutureCallback
另外建议把concurrent-futures-ktx的版本和上面的concurrent-futures统一为1.1.0,避免版本冲突。
二、配置mExecutor
mExecutor是用来执行后台耗时任务的线程池,AppSearch的创建会话、设置Schema、写入文档等操作都不能在主线程执行,所以需要配置一个后台线程池:
方式1:创建单线程线程池
这是最简单的后台线程配置,适合轻量的AppSearch操作:
import java.util.concurrent.Executors private val mExecutor = Executors.newSingleThreadExecutor()
方式2:使用固定大小线程池
如果有多个并发的AppSearch操作,可以用固定线程数的线程池:
import java.util.concurrent.Executors private val mExecutor = Executors.newFixedThreadPool(2)
注意:绝对不要用主线程作为mExecutor,否则会触发ANR(应用无响应)。
三、使用Kotlin协程替代Futures(更优雅的方案)
既然你用的是Kotlin,协程是比Futures更简洁的异步处理方式,完全可以替代原有的回调式代码,步骤如下:
1. 添加协程依赖
确保项目中已添加这些依赖:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2" // 用于lifecycleScope implementation "androidx.concurrent:concurrent-futures-ktx:1.1.0"
2. 协程版本的代码实现
利用asDeferred()扩展函数将ListenableFuture转换为协程的Deferred,再用await()等待结果,代码逻辑更线性:
import android.util.Log import androidx.appsearch.app.PutDocumentsRequest import androidx.appsearch.app.SetSchemaRequest import androidx.appsearch.localstorage.LocalStorage import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext // 在Activity/Fragment中使用lifecycleScope自动绑定生命周期,避免内存泄漏 lifecycleScope.launch { try { // 创建搜索会话(切换到IO线程执行耗时操作) val session = withContext(Dispatchers.IO) { LocalStorage.createSearchSession( LocalStorage.SearchContext.Builder(this@YourActivity, "notes_app") .build() ).await() } // 设置Schema withContext(Dispatchers.IO) { session.setSchema( SetSchemaRequest.Builder().addDocumentClasses(Note::class.java) .build() ).await() } // 写入文档并处理结果 val putResult = withContext(Dispatchers.IO) { session.put( PutDocumentsRequest.Builder().addDocuments(note).build() ).await() } // 处理成功/失败结果,这里在主线程可以直接更新UI val successfulResults = putResult.successes val failedResults = putResult.failures } catch (t: Throwable) { Log.e(TAG, "AppSearch操作失败", t) } }
说明:
lifecycleScope会自动跟随Activity/Fragment的生命周期销毁,避免内存泄漏;withContext(Dispatchers.IO)将耗时操作切换到后台线程,不阻塞主线程;- 统一的
try-catch可以处理所有异常,比回调式的FutureCallback更易维护。
内容的提问来源于stack exchange,提问作者Itoun
相关产品推荐
相关产品推荐

