使用GoogleCredentials创建Google Drive文件夹时应用崩溃求助
解决Android中Google Drive创建文件夹时的NetworkOnMainThreadException异常
在Android项目中用Kotlin实现了GoogleCredentials授权并在Google Drive创建文件夹的功能,已添加所需依赖和INTERNET权限,但点击按钮调用signIn函数时,执行googleDriveService.files().create(folderMetadata).execute()导致应用崩溃,错误日志显示android.os.NetworkOnMainThreadException。
依赖配置
implementation("com.google.android.gms:play-services-auth:21.2.0") implementation("com.google.api-client:google-api-client:2.5.0") implementation("com.google.apis:google-api-services-drive:v3-rev20240521-2.0.0") implementation("com.google.http-client:google-http-client-android:1.26.0")
相关代码
// Google Sign in fun signIn(context: Context) { val authorizationRequest = AuthorizationRequest.builder().setRequestedScopes(SCOPES).build() Identity.getAuthorizationClient(context as Activity).authorize(authorizationRequest) .addOnSuccessListener { authorizationResult -> if (authorizationResult.hasResolution()) { // 需要用户授权 val pendingIntent = authorizationResult.pendingIntent try { startIntentSenderForResult( context, pendingIntent!!.intentSender, 999, null, 0, 0, 0, null ) } catch (e: IntentSender.SendIntentException) { Log.i("@@@", "Authorization failed: " + e.message) } } else { // 授权成功,执行操作 Log.i("@@@", "Access granted") val token = authorizationResult.accessToken val credentials = GoogleCredentials.create(AccessToken(token, null)) val requestInitializer = HttpCredentialsAdapter(credentials) val googleDriveService = Drive.Builder( AndroidHttp.newCompatibleTransport(), GsonFactory(), requestInitializer ) .setApplicationName(context.getString(R.string.app_name)) .build() Log.i("@@@", googleDriveService.toString()) try { // 创建Google Drive文件夹 // 文件夹元数据 val folderMetadata = File().setMimeType("application/vnd.google-apps.folder") .setParents(listOf(ROOT)) .setName(FOLDER_NAME).setStarred(true) .setFolderColorRgb("#FF0000") // 红色 // 创建文件夹(此处崩溃,错误信息:null) googleDriveService.files().create(folderMetadata).execute() } catch (e: Exception) { Log.e("@@@", e.message.toString()) } } }.addOnFailureListener { e -> Log.e("@@@", "Failed to authorize", e) } }
完整异常日志
null android.os.NetworkOnMainThreadException at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1675) at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:115) at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103) at java.net.InetAddress.getAllByName(InetAddress.java:1152) at com.android.okhttp.Dns$1.lookup(Dns.java:41) at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:178) at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:144) at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:86) at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:176) at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128) at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97) at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289) at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:262) at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:219) at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:30) at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:113) at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:84) at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1012) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:565) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:506) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:616) at mdc.auMenu.ui.account.GDriveKt.signIn$lambda$0(GDrive.kt:98) at mdc.auMenu.ui.account.GDriveKt.$r8$lambda$p_pBQS_xClgWTOPLtc5ZI1mWzwo(Unknown Source:0) at mdc.auMenu.ui.account.GDriveKt$$ExternalSyntheticLambda0.invoke(D8$$SyntheticClass:0) at mdc.auMenu.ui.account.GDriveKt.signIn$lambda$1(GDrive.kt:54) at mdc.auMenu.ui.account.GDriveKt.$r8$lambda$z9STuCnUdP6vzHpOxi9Ibd4ex84(Unknown Source:0) at mdc.auMenu.ui.account.GDriveKt$$ExternalSyntheticLambda1.onSuccess(D8$$SyntheticClass:0) at com.google.android.gms.tasks.zzm.run(com.google.android.gms:play-services-tasks@@18.1.0:1) 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.app.ActivityThread.main(ActivityThread.java:8177) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
解决方案
NetworkOnMainThreadException是因为Android禁止在主线程执行耗时网络操作,会导致界面卡顿甚至ANR。解决核心是把创建文件夹的网络请求放到后台线程执行,以下是三种常用方案:
方案1:使用AsyncTask(简单场景适用,Android 11后标记废弃但仍可使用)
替换原代码中创建文件夹的try-catch块:
AsyncTask.execute { try { val folderMetadata = File().setMimeType("application/vnd.google-apps.folder") .setParents(listOf(ROOT)) .setName(FOLDER_NAME).setStarred(true) .setFolderColorRgb("#FF0000") googleDriveService.files().create(folderMetadata).execute() // 操作成功后回到主线程更新UI (context as Activity).runOnUiThread { Toast.makeText(context, "文件夹创建成功", Toast.LENGTH_SHORT).show() } } catch (e: Exception) { Log.e("@@@", e.message ?: "未知错误") (context as Activity).runOnUiThread { Toast.makeText(context, "创建失败:${e.message}", Toast.LENGTH_SHORT).show() } } }
方案2:使用Kotlin协程(推荐方案,更简洁)
先确保添加协程依赖(未添加则加入):
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
再替换创建文件夹的代码:
CoroutineScope(Dispatchers.IO).launch { try { val folderMetadata = File().setMimeType("application/vnd.google-apps.folder") .setParents(listOf(ROOT)) .setName(FOLDER_NAME).setStarred(true) .setFolderColorRgb("#FF0000") googleDriveService.files().create(folderMetadata).execute() // 切换到主线程更新UI withContext(Dispatchers.Main) { Toast.makeText(context, "文件夹创建成功", Toast.LENGTH_SHORT).show() } } catch (e: Exception) { Log.e("@@@", e.message ?: "未知错误") withContext(Dispatchers.Main) { Toast.makeText(context, "创建失败:${e.message}", Toast.LENGTH_SHORT).show() } } }
方案3:手动创建Thread
直接创建后台线程执行网络请求:
Thread { try { val folderMetadata = File().setMimeType("application/vnd.google-apps.folder") .setParents(listOf(ROOT)) .setName(FOLDER_NAME).setStarred(true) .setFolderColorRgb("#FF0000") googleDriveService.files().create(folderMetadata).execute() // 回到主线程处理结果 (context as Activity).runOnUiThread { Toast.makeText(context, "文件夹创建成功", Toast.LENGTH_SHORT).show() } } catch (e: Exception) { Log.e("@@@", e.message ?: "未知错误") (context as Activity).runOnUiThread { Toast.makeText(context, "创建失败:${e.message}", Toast.LENGTH_SHORT).show() } } }.start()
内容的提问来源于stack exchange,提问作者user26453386
相关产品推荐
相关产品推荐

