質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
バックアップ

バックアップとは、保存データやプログラムの複製を異なる記録装置などへ保存することを言います。バックアップを取っておくことで、機器のトラブルでデータが損傷するなどの不測の事態にもデータを複製することが可能です。

Google ドライブ

Google ドライブは、Google社が提供するオンラインストレージサービス。オンラインストレージ上に、画像や動画、テキスト、Word/PDFのファイルなどさまざまなファイル保存することができます。また、他のユーザーと共有することも可能です。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

アップロード

アップロードは特定のファイルをウェブサーバに送るプロセスのことを指します。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

2回答

1112閲覧

Google Driveへのアップロードが正しくできない

bluvenz

総合スコア22

バックアップ

バックアップとは、保存データやプログラムの複製を異なる記録装置などへ保存することを言います。バックアップを取っておくことで、機器のトラブルでデータが損傷するなどの不測の事態にもデータを複製することが可能です。

Google ドライブ

Google ドライブは、Google社が提供するオンラインストレージサービス。オンラインストレージ上に、画像や動画、テキスト、Word/PDFのファイルなどさまざまなファイル保存することができます。また、他のユーザーと共有することも可能です。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

アップロード

アップロードは特定のファイルをウェブサーバに送るプロセスのことを指します。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2022/05/26 08:20

編集2022/05/27 01:43

前提

Kotlinを使用してGoogle Driveにファイルをバックアップ(アップロード)するアプリを作成しています。
しかし、Google認証からアップロードの流れが上手くいっていないようで、アップロード操作を2回行わないとファイルがアップロードされずに困っています。

エラーも出力されており、エラー内容を調べてもみましたが原因究明には至りませんでした。

実現したいこと

  • 1度のアップロード操作でファイルがアップロードされるようにしたい。
  • 発生しているエラーを解消したい。

該当のソースコード

MainActivity

1override fun onNavigationItemSelected(item: MenuItem): Boolean { 2 Log.d("TAG", "nav_backup: 1") 3 signInGoogle() 4 Log.d("TAG", "nav_backup: 2") 5 6 Log.d("TAG", "nav_backup: 3") 7 backupFile() 8 Log.d("TAG", "nav_backup: 4") 9} 10 11 private fun signInGoogle() { 12 Log.d("TAG", "signInGoogle: 1") 13 14 val googleSignInOptions = 15 GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 16 .requestScopes(Scope(DriveScopes.DRIVE_FILE)) 17 .requestEmail() 18 .build() 19 val googleSignInClient = GoogleSignIn.getClient(this, googleSignInOptions) 20 googleSignInClient.let { 21 Log.d("TAG", "signInGoogle: 2") 22 val intent = it.signInIntent 23 driveContent.launch(intent) 24 Log.d("TAG", "signInGoogle: 3") 25 } 26 } 27 28 private val driveContent = 29 registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { 30 Log.d("TAG", "driveContent: 1") 31 if (it.resultCode == Activity.RESULT_OK && it.data != null) { 32 // ログイン成功 33 Log.d("TAG", "driveContent: 2") 34 connectDrive(it.data!!) 35 Log.d("TAG", "driveContent: 3") 36 } else { 37 // ログイン失敗 or キャンセル 38 } 39 } 40 41 private fun connectDrive(intent: Intent) { 42 Log.d("TAG", "connectDrive: 1") 43 GoogleSignIn.getSignedInAccountFromIntent(intent) 44 .addOnSuccessListener { 45 Log.d("TAG", "connectDrive: 2") 46 drive = GoogleDriveHelper.getGoogleDriveService( 47 this, it, getString(R.string.app_name)) 48 49 Log.d("TAG", "connectDrive: 2") 50 googleDriveHelper = GoogleDriveHelper(drive) 51 52 Log.d("TAG", "connectDrive: 3") 53 //backupFile() 54 } 55 .addOnFailureListener { 56 Log.w("Sign in failed", "connectDrive:") 57 } 58 } 59 60 private fun backupFile() { 61 Log.d("TAG", "backupFile: 1") 62 63 // アップロード処理 64 }

ログ結果

nav_backup: 1 signInGoogle: 1 signInGoogle: 2 signInGoogle: 3 nav_backup: 2 nav_backup: 3 backupFile: 1 nav_backup: 4 ※エラーメッセージ(後述) driveContent: 1 driveContent: 2 connectDrive: 1 driveContent: 3 ※エラーメッセージ(後述) connectDrive: 2 connectDrive: 2 connectDrive: 3

エラーメッセージ(前述のもの)

2022-05-26 17:08:25.768 2076-2950/com.google.android.gms.persistent E/SQLiteDatabase: Error inserting service_kind=0 source=16 tag=Measurement.PackageMeasurementTaskService.UPLOAD_TASK_TAG requires_charging=0 target_package=com.google.android.gms source_version=202414000 required_network_type=0 flex_time=437000 persistence_level=1 target_class=com.google.android.gms.measurement.PackageMeasurementTaskService runtime=1653552505760 retry_strategy={"maximum_backoff_seconds":{"3600":0},"initial_backoff_seconds":{"30":0},"retry_policy":{"0":0}} preferred_network_type=1 required_idleness_state=0 preferred_charging_state=1 last_runtime=0 period=875000 task_type=0 job_id=-1 user_id=0 android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: pending_ops.tag, pending_ops.target_class, pending_ops.target_package, pending_ops.user_id (code 2067) at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method) at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:780) at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788) at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86) at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1471) at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1341) at aqui.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):175) at aqtk.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):182) at aqtk.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):23) at aqtk.a(:com.google.android.gms@202414022@20.24.14 (040700-319035315):177) at aqpu.run(:com.google.android.gms@202414022@20.24.14 (040700-319035315):9) at soy.b(:com.google.android.gms@202414022@20.24.14 (040700-319035315):12) at soy.run(:com.google.android.gms@202414022@20.24.14 (040700-319035315):7) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at sux.run(:com.google.android.gms@202414022@20.24.14 (040700-319035315):0) at java.lang.Thread.run(Thread.java:818)

試したこと

  • connectDrive内のコメントアウトしている//backupFile()のタイミングで処理を行った時は希望通りの処理が行われます。
  • 分からないながらもLogを埋め込みcoroutineを使ったりしてみましたが実現できませんでした。
  • 現在、ログ内容から認証される前にアップロード処理が走ってしまい、ファイルがアップロードされていないのではと考えています。

(そのため、認証後となる2回目はアップロードされると予想しています。)

補足情報(FW/ツールのバージョンなど)

アプリ内で撮影した写真データをバックアップしたく、初めてGoogle Driveの操作に挑戦しています。
(バックアップ自体は「Google Drive内」と「端末内」で選択できる仕様を考えています。)
試行錯誤のため根本的な間違いをしていたらすみません。

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ログ内容から認証される前にアップロード処理が走ってしまい、ファイルがアップロードされていないので

この推測はおそらく正しいような気がします。

というのも、 registerForActivityResultというのは従来のonActivityResultの代わりになるものと捉えてもらうと、launch()したタイミングで処理をブロックせず、そのまま流れていきます。(別スレッドでGoogleの認証~Driveへの接続が走ると捉えてしまってもいいかもしれません。)
また、そうでなくともconnectDrive()内の getSignedInAccountFromIntent()Taskであり、やはり処理を中断せず、処理を完了した時点で登録したリスナが割り込みます。

すると、質問者様の推測通り、認証処理をスタートさせ、それを待つことなくバックアップ処理へと進んでいってしまいます。

さて、ではどうすればよいかというと、 suspendCancellableCoroutineというものを利用します。
詳しい説明は省きますが、簡単に言ってしまうと 処理完了まで待機させるものとお考え下さい。
また、待機させるために関数をsuspend修飾し、Coroutineを使っていきます。

ログインに失敗したときに例外を吐かせるかどうかはさておき、大まかな実装は次のようになると思います。

override fun onNavigationItemSelected(item: MenuItem): Boolean { CoroutineScope(Dispatchers.Main).launch{ if(signinGoogle()){ backupFile() } } } private var continuation: CancellableContinuation<Boolean>? = null /** * ログイン成功時にtrue, 失敗時にfalseを返す */ private suspend fun signInGoogle(): Boolean{ return suspendCancellableCoroutine{ continuation = it val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(Scope(DriveScopes.DRIVE_FILE)) .requestEmail() .build() GoogleSignIn.getClient(this, googleSignInOptions).let { client -> driveContent.launch(client.signinIntent) } continuation.omvokeCancellation{ continuation = null } } } private val driveContent = ..... ..... else { // ログイン失敗 or キャンセル continuation?.resume(false) } private fun connectDrive(intent: Intent) { Log.d("TAG", "connectDrive: 1") GoogleSignIn.getSignedInAccountFromIntent(intent) .addOnSuccessListener { drive = GoogleDriveHelper.getGoogleDriveService(this, it, getString(R.string.app_name)) googleDriveHelper = GoogleDriveHelper(drive) continuation?.resume(true) } .addOnFailureListener { continuation?.resume(false) } }

実際に手元で動かさずに、机上で書いているのでもしかしたら不具合等あるかもしれないので、ひとつの参考程度にとどめておいていただけると。

投稿2022/09/29 07:17

milkcocoa0902

総合スコア8

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

42であなたの問題は解決します。googleで検索したので間違いないです。
参考:The Answer to the Ultimate Question of Life, the Universe, and Everything is 42

投稿2022/05/26 08:23

can110

総合スコア38266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問