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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Android

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

Kotlin

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

Q&A

解決済

1回答

157閲覧

DBから画像のUri取得してCoil使って表示したい

uminari

総合スコア5

Android

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

Kotlin

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

0グッド

0クリップ

投稿2024/02/28 13:56

編集2024/02/28 14:02

実現したいこと

DBから画像のUri取得してCoil使って表示したい

発生している問題・分からないこと

アプリを再起動した時に、DBに保存している画像が表示されない

①Androidの標準ギャラリーで画像を選択し、画像のUri取得
②UriをDBに保存
③DBからUri取得して、LiveDataに保存
④Composable側でLiveData見るようにして、Coilで画像を表示(LazyVerticalGrid()で画像をGrid表示)
⑤画像が表示される
⑥一度アプリをと落とす
⑦画像が1枚も表示されない。★
ログ上では、Uriも取れているが、なぜか表示されない。
⑧Androidの標準ギャラリーで既にDBに保存済みの画像を選択し、画像のUri取得
⑨Grid画面に遷移すると、画像が表示される
表示される画像は特定の画像のみで、
アプリを落とした後に選択した画像と同じ、アプリを落とす前に保存した画像が表示される。
(Androidの標準ギャラリーで画像を選択した後は画像が表示される)
その他の保存した画像は表示されない。

該当のソースコード

Kotlin

1class MainActivity : ComponentActivity() { 2 override fun onCreate(savedInstanceState: Bundle?) { 3 super.onCreate(savedInstanceState) 4 5 val viewModel: AddWantViewModel by viewModels { 6 AddWantViewModelFactory(application) 7 } 8 val launcher = registerForActivityResult(ActivityResultContracts.OpenDocument()) { 9 Log.d("Main Activity", "launcher launch") 10 viewModel.setImage(it) 11 } 12 13 setContent { 14 WantNoteTheme { 15 // A surface container using the 'background' color from the theme 16 Surface( 17 modifier = Modifier.fillMaxSize(), 18 color = MaterialTheme.colorScheme.background 19 ) { 20 WantNoteApp( 21 startImageGallery = { launcher.launch(arrayOf("image/*")) } 22 ) 23 } 24 } 25 } 26 } 27}

Kotlin

1@Composable 2fun WantNoteApp( 3 startImageGallery: () -> Unit 4) { 5 val navController = rememberNavController() 6 7 Scaffold( 8 floatingActionButton = { 9 FloatingActionButton( 10 onClick = { 11 navController.navigate(Screens.Add.route) 12 } 13 ) { 14 Icon(imageVector = Icons.Filled.Add, contentDescription = null) 15 } 16 } 17 ) { 18 Spacer(modifier = Modifier.padding(it)) 19 AppNavigation( 20 navController, 21 startImageGallery = startImageGallery 22 ) 23 } 24}

Kotlin

1@Composable 2fun AppNavigation( 3 navController: NavHostController, 4 startImageGallery: () -> Unit 5) { 6 NavHost( 7 navController = navController, 8 startDestination = Screens.Home.route, 9 builder = { 10 composable(Screens.Home.route) { 11 WantList( 12 onClickItem = { navController.navigate(Screens.Preview.route) } 13 ) 14 } 15 composable(Screens.Add.route) { 16 AddWant( 17 onClickAdd = { navController.navigate(Screens.Home.route) }, 18 onClickSetImage = startImageGallery 19 ) 20 } 21 composable(Screens.Preview.route) { 22 PreviewWant( 23 onClickBack = { navController.navigateUp() }, 24 onClickEdit = { navController.navigate(Screens.Edit.route) } 25 ) 26 } 27 composable(Screens.Edit.route) { 28 EditWant( 29 onClickBack = { navController.navigateUp() }, 30 onClickChange = { navController.navigate(Screens.Home.route) } 31 ) 32 } 33 } 34 ) 35} 36 37sealed class Screens( 38 val route: String 39) { 40 object Home: Screens("home") 41 object Add: Screens("add") 42 object Preview: Screens("preview") 43 object Edit: Screens("edit") 44}

Kotlin

1@Composable 2fun WantList( 3 onClickItem: () -> Unit 4) { 5 var viewModel: WantListViewModel? = null 6 LocalViewModelStoreOwner.current?.let { 7 viewModel = viewModel( 8 it, 9 "WantListViewModel", 10 WantListViewModelFactory(LocalContext.current.applicationContext as Application) 11 ) 12 } 13 val items = viewModel?.items?.observeAsState() 14 println("WantList items=$items") 15 16 LazyVerticalGrid( 17 columns = GridCells.Adaptive(minSize = 150.dp), 18 content = { 19 val list = items?.value 20 Log.d("WantList", "list=$list") 21 if (!list.isNullOrEmpty()) { 22 items(list) { item -> 23 Log.d("WantList", "item=$item") 24 GridItem( 25 imageUrl = item.imageUri, 26 onClickItem = onClickItem 27 ) 28 } 29 } 30 } 31 ) 32} 33 34@Composable 35fun GridItem( 36 imageUrl: String, 37 onClickItem: () -> Unit 38) { 39 Log.d("GridItem", "imageUri=${Uri.parse(imageUrl)}") 40 Surface( 41 modifier = Modifier 42 .padding(1.dp) 43 .clickable { onClickItem() } 44 ) { 45 Image( 46 painter = rememberAsyncImagePainter(model = Uri.parse(imageUrl)), 47 contentDescription = null, 48 contentScale = ContentScale.Crop, 49 modifier = Modifier.size(150.dp) 50 ) 51 } 52}

Kotlin

1class WantListViewModel(private val application: Application): ViewModel() { 2 3 companion object { 4 private val mutex = Mutex() 5 } 6 7 private val db = WantDatabase.getInstanse(application.applicationContext) 8 private val wantRepository = WantRepository(db) 9 10 private var _items = MutableLiveData<List<WantItem>>() 11 val items: LiveData<List<WantItem>> 12 get() = _items 13 14 init { 15 fetch() 16 } 17 18 fun fetch() { 19 viewModelScope.launch { 20 mutex.withLock { 21 withContext(Dispatchers.IO) { 22 _items.postValue(wantRepository.getAll()) 23 } 24 } 25 } 26 } 27}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

ログでは値が取れていることは確認済み
Log.d("GridItem", "imageUri=${Uri.parse(imageUrl)}")
println("WantList items=$items")

補足

特になし

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

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

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

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

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

jimbe

2024/02/28 14:56

選択・保存した画像へのアクセス権をアプリが取ってないのではないでしょうか。
uminari

2024/02/29 14:34

以下のような挙動になります。 画像を選択→DBに保存→画像をDBから取得して表示→一度アプリを落とす→画像がすべて表示されない アプリを落とさなければ、画像は表示されるので、アクセス権は関係なさそうに見えますが、いかがでしょうか。
jimbe

2024/02/29 16:36 編集

画像をギャラリーで選択すると一時的なアクセス権がアプリに設定されますので画像は表示出来ますが、アプリを落とすとアクセス権が消えますので再起動すると URL が合っていても読めませんので表示出来ないと思います。 画像の取得時等に例外は発生していないでしょうか。 [Android13の写真選択ツールを導入しようとしてやめた話] https://qiita.com/all_fort/items/7a933439fcc576918160 [Android Studio パーミッションに関して] https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13201882568 [Android Studio アプリ開発] https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13190716858
uminari

2024/03/09 02:17

ありがとうございます。解決しました。 仰る通り、Uriのアクセス件の問題だったでした。
guest

回答1

0

自己解決


ギャラリーで画像選択した際に、その時のみドキュメントに対するアクセス権を発行し、起動元のアプリを再起動するまで保持されるので、再起動してしまうと、permissionは破棄され、再度アクセスすることは不可能ぽい。

[権限を保持する]
https://developer.android.com/training/data-storage/shared/documents-files?hl=ja#grant-access-directory

MainActivityでUri取得したタイミングで、takePersistableUriPermissionで権限を永続化できるらしいが、同じエラー発生する。
ドキュメントを移動 or 削除すると再度、永続化しないとダメらしいが、特にしていないと思うので、謎。


UriをDBに保存することをやめて、Uri取得した時にBitmapに変換して、ローカルのストレージに保存し、そのパスをDBに保存することで、表示できた。

投稿2024/03/09 02:26

uminari

総合スコア5

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問