Androidで、Firebase(FirebaseStorage,Realtimedatabase)を使用して画像やテキストなどを表示するアプリを開発しています。
テキストデータはRealtimedatabase、画像はdownloadURLをRealtimedatabaseに保持して、そこから画像の実体をFirebaseStorageから取ってくるようにしております。
しかし、実装してみると画像が表示されなくなったりテキストを表示されるべきところに画像が表示されるなど意図しない挙動が起きています。
原因として、推測されるのは以下のように画像の取得で用いられるFirebaseStorageとそれ以外の取得に用いられるRealtimedatabaseそれぞれが非同期処理で動いているためかと思われます。
例えば、realtimeDatabase側の「for(DataSnapshot ds・・・」の4ループ目が画像1だったとして、その画像データの取得(FireStorage側)が完了した時、Realtimedatabaseが7ループ目まで進んでいたとしたら、本来4ループ目のmessageDataBeanに画像データを入れるはずが7ループ目のmessageDataBeanを更新してしまうということです。
これを防ぐには例えば4ループ目で取得し始めた画像を取得完了後に、4ループ目のList<messageDataBean>の要素(messageDataBean)の画像フィールドにセット、8ループ目で取得しようとした画像を8ループ目のListの要素にセットというように処理を実装する必要があるのですが、その方法を教えていただけないでしょうか。
Java
DatabaseReferense ref = ・・・・; Bitmap imgBitmap; ArrayList<MessageDataBean> messageDataBean = new ArrayList<MessageDataBean>(); //DBを読み出し(画像以外はRealtimedatabase) ref.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { for(DataSnapshot ds : dataSnapshot.getChildren()){ String txtData1; String txtData2; String msgType = ds.child("type").getValue(); if(msgType.equals("txt")){//テキストの場合 txtData1 = ds.child("txt1").getValue(); txtData2 = ds.child("txt2").getValue(); }else if(msgType.equals("img")){//画像の場合 //画像のダウンロードURL String downloadURL = String.valueOf(ds.child("img_dl_url").getValue()); StorageReference images = FirebaseStorage.getInstance().getReferenceFromUrl(downloadURL); //ダウンロードの最大のサイズを指定する final long ONE_MEGABYTE = 1024 * 1024; images.getBytes(ONE_MEGABYTE).addOnSuccessListener(new OnSuccessListener<byte[]>() { @Override public void onSuccess(byte[] bytes) { // 画像のダウンロード成功 imgBitmap = OtherUtils.createBitmap(bytes,1024,1024); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // 画像のダウンロード失敗 } }); } MessageDataBean messageDataBean = new MessageDataBean( txtData1, txtData2, imgBitmap, ); messageDataBeanList.add(messageDataBean); show(messageDataBeanList);//表示内容更新処理 } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { } });
まだ回答がついていません
会員登録して回答してみよう