Android Kotlin中Google Drive API的files().list()间歇性返回Null
问题描述
在Android API 34的Kotlin应用中使用Google Drive API,已成功通过API创建名为Inventory_Backup的文件夹,该文件夹能在Google Drive网页端查看,也可正常上传下载文件。但后续调用files().list()接口验证文件夹是否存在时,结果间歇性返回Null,多数情况返回Null,偶尔能得到预期值。
Gradle依赖
implementation 'com.google.android.gms:play-services-auth:19.0.0' implementation 'com.google.http-client:google-http-client-gson:1.26.0' implementation('com.google.api-client:google-api-client-android:1.26.0') { exclude group: 'org.apache.httpcomponents' } implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0') { exclude group: 'org.apache.httpcomponents' }
Manifest权限配置
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
创建Drive服务代码
val googleDriveService = Drive.Builder( AndroidHttp.newCompatibleTransport(), GsonFactory(), credential ) .setApplicationName("House Inventory") .build() // DriveServiceHelper封装所有REST API和SAF功能,处理点击事件前必须实例化 mDriveServiceHelper = GoogleDriveServiceHelper(googleDriveService)
GoogleDriveServiceHelper类初始化代码
class GoogleDriveServiceHelper(driveService: Drive) { private val mDriveService: Drive = driveService private val FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" private val FOLDER_NAME = "Inventory_Backup" private val FILE_MIME_TYPE = "application/zip" var FILE_NAME = ""
创建文件夹代码
private val FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" private val FOLDER_NAME = "Inventory_Backup" fun createFolder(): Task<String> { val tcs = TaskCompletionSource<String>() val service = Executors.newFixedThreadPool(1) val metadata = File() .setParents(listOf("root")) .setMimeType(FOLDER_MIME_TYPE) .setName(FOLDER_NAME) service.execute { val googleFolder: File? try { googleFolder = mDriveService.files().create(metadata).execute() } catch (e: IOException) { e.printStackTrace() throw IOException("Null result when requesting Folder creation.") } val finalResult = googleFolder.id Handler(Looper.getMainLooper()).postDelayed({ tcs.setResult(finalResult) }, 1000) } return tcs.task }
验证文件夹存在的代码
val isFolderPresent: Task<String> get() = getFolderPresent() fun getFolderPresent(): Task<String> { val tcs = TaskCompletionSource<String>() val service = Executors.newFixedThreadPool(1) service.execute { var result: FileList? = null try { result = mDriveService.files().list() .setQ("mimeType='$FOLDER_MIME_TYPE' and trashed=false") .execute() // 此处result间歇性为Null } catch (e: IOException) { e.printStackTrace() } var finalResult = "" if (result != null) for (file in result.files) { if (file.name == FOLDER_NAME) finalResult = file.id } Handler(Looper.getMainLooper()).postDelayed({ tcs.setResult(finalResult) }, 1000) } return tcs.task }
解决方案
1. 精准优化查询条件
当前查询未限定父目录为根目录,且未直接过滤文件夹名称,可能搜索到其他目录下的同名文件夹,同时API默认分页返回结果,容易遗漏目标文件夹。修改查询语句:
.setQ("mimeType='$FOLDER_MIME_TYPE' and name='$FOLDER_NAME' and 'root' in parents and trashed=false")
2. 处理分页结果
Google Drive API默认只返回100条结果,需循环获取所有分页数据,避免遗漏:
fun getFolderPresent(): Task<String> { val tcs = TaskCompletionSource<String>() Executors.newSingleThreadExecutor().execute { var finalResult = "" var pageToken: String? = null try { do { val result = mDriveService.files().list() .setQ("mimeType='$FOLDER_MIME_TYPE' and name='$FOLDER_NAME' and 'root' in parents and trashed=false") .setPageToken(pageToken) .execute() result.files?.forEach { file -> finalResult = file.id } pageToken = result.nextPageToken } while (pageToken != null) } catch (e: IOException) { e.printStackTrace() } Handler(Looper.getMainLooper()).post { tcs.setResult(finalResult) } } return tcs.task }
3. 移除不必要的延迟
创建文件夹和验证逻辑中的postDelayed(1000)无实际意义,反而可能导致时序问题,直接在任务完成后立即回调:
- 创建文件夹代码修改为:
Handler(Looper.getMainLooper()).post { tcs.setResult(finalResult) }
- 验证文件夹代码同理移除延迟。
4. 更新依赖版本
当前使用的Drive API版本较旧,存在兼容性隐患,建议更新至最新稳定版:
implementation 'com.google.android.gms:play-services-auth:20.7.0' implementation 'com.google.http-client:google-http-client-gson:1.43.3' implementation('com.google.api-client:google-api-client-android:2.0.1') { exclude group: 'org.apache.httpcomponents' } implementation('com.google.apis:google-api-services-drive:v3-rev20240512-2.0.1') { exclude group: 'org.apache.httpcomponents' }
5. 检查认证有效性
确保credential未过期,调用API前可检查认证状态:
if (!credential.refreshToken) { // 触发重新认证流程 }
内容的提问来源于stack exchange,提问作者jetberrocal
相关产品推荐
相关产品推荐

