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

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

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

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Android

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

Kotlin

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

Q&A

解決済

1回答

1570閲覧

Firebase Realtime Databaseでのデータ取得について【Android】

sink66

総合スコア88

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Android

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

Kotlin

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

0グッド

0クリップ

投稿2018/01/07 12:48

編集2018/01/07 12:55

やりたいこと

Firebaseにある特定のデータを取得してRecyclerViewに表示したいです。
具体的には、Realtime Database上でFirebaseAuthのuidを持つuserを探し、そのuserが持っているfriendsの一覧を表示したいです。

問題と質問

できるにはできたのですが、あまりにも無理矢理な感が強く、とても正しい方法だと思えません。
もっと良い方法を教えて頂きたいと思っています。

現在のコード

  • Firebase Realtime Database

json

1{ 2 "users" : { 3 "userkey01" : { // push()すると作られる固有のキーです 4 "friends" : { 5 "userkey02" : "user2name" // このユーザーのフレンドがfirebase上のキーとnameの値で格納されています 6 }, 7 "name" : "user1", 8 "uid" : "user1uid" // FirebaseAuthのUIDです 9 }, 10 "userkey02" : { 11 "friends" : { 12 "userkey01" : "user1name" 13 }, 14 "name" : "user2", 15 "uid" : "user2uid" 16 } 17 } 18}
  • Fragmentのコード抜粋

kotlin

1override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { 2 val view = inflater!!.inflate(R.layout.fragment_friend, container, false) 3 4 val recyclerView = view.friend_recycler 5 recyclerView.layoutManager = LinearLayoutManager(activity) 6 7 val array = ArrayList<String>() // このArrayListにfriendのnameが入ります 8 9 val databaseRef: DatabaseReference = FirebaseDatabase.getInstance().reference 10 val currentUserUid = FirebaseAuth.getInstance().currentUser!!.uid 11 12 // 現在ログインしているユーザーのuidから、それを持つノードを検索しています 13 val currentUserRef = databaseRef.child(FirebaseEntityName.USER).orderByChild("uid").equalTo(currentUserUid) 14 15     // 検索したユーザーのノードを一度だけ取得します 16 currentUserRef.addListenerForSingleValueEvent(object : ValueEventListener { 17 override fun onDataChange(p0: DataSnapshot?) { 18 19 // 見つかっていればfirstChildにノードが入るはずなので、格納します 20 val firstChild = p0!!.children.iterator().next() 21 22 // 見つかったuserのkeyを使用して、userの持つfriendsの参照を取得します 23 var friends = databaseRef.child(FirebaseEntityName.USER).child(firstChild.key).child("friends") 24 25 // friendsのデータを取得します 26 friends.addListenerForSingleValueEvent(object : ValueEventListener { 27 28 override fun onDataChange(p0: DataSnapshot?) { 29 30 // 見つかっていれば格納します 31 // 現在データが一つしかありませんが、複数の予定なので、iteratorを使ってループで回すことになると思います。 32 val firstChild = p0!!.children.iterator().next() 33 34 // ArrayListに名前を追加して、notifyItemChanged()でrecyclerViewに変更を通知します 35 array.add(firstChild.value) 36 recyclerView.adapter.notifyItemChanged(array.size - 1) 37 } 38 39 override fun onCancelled(p0: DatabaseError?) { 40 Log.d("cancelled", "cancelled") 41 } 42 }) 43 } 44 45 override fun onCancelled(p0: DatabaseError?) { 46 Log.d("cancelled", "cancelled") 47 } 48 }) 49 50 val itemDecoration = DividerItemDecoration(activity, DividerItemDecoration.VERTICAL) 51 recyclerView.addItemDecoration(itemDecoration) 52 53 recyclerView.adapter = FriendAdapter(activity,array) 54 return view 55 }

よろしくお願いします。

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

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

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

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

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

guest

回答1

0

自己解決

1

onDataChange()をネストさせて複雑なクエリを作るというのは、それほど的を外した考えではなかったようです

  • 全てを組み合わせる

https://firebase.google.com/docs/database/admin/retrieve-data?hl=ja

  • Firebase データベースでの結合 - SQL 開発者用 Firebase Databese 第5回

https://www.youtube.com/watch?v=Idu9EJPSxiY

2

ただ、今回の例ではval firstChild = p0!!.children.iterator().next()の時点でデータが取得出来ているので、複雑に考えずこのvalueを使用すれば済みました
このときgetValue()を使用してオブジェクトとマッピングするのが常套手段であるようですが、私のモデルのせいか、このメソッドは例外が出て動きませんでした

  • モデル

kotlin

1data class User( 2 var uid: String, 3 var name: String, 4 var friends: Map<String, String> 5)
  • 例外コード

kotlin

1currentUserRef.addListenerForSingleValueEvent(object : ValueEventListener { 2 override fun onDataChange(p0: DataSnapshot?) { 3 val firstChild = p0!!.children.iterator().next() 4 5 // 以下、どちらも com.google.firebase.database.DatabaseException: Class com.example.model.entity.User is missing a constructor with no arguments 6 val value: User? = p0!!.getValue(User::class.java) 7 val value: User? = firstChild.getValue(User::class.java) 8 } 9}

3

いろいろ試したのですがどうにもこの例外が解決できないので、
getValue()ではなくMoshiというライブラリを使ってパースしたところ、うまく行きました

  • 解決

kotlin

1currentUserRef.addListenerForSingleValueEvent(object : ValueEventListener { 2 override fun onDataChange(p0: DataSnapshot?) { 3 4 val firstChild = p0!!.children.iterator().next() 5 val moshi = Moshi.Builder().build() 6 val adapter = moshi.adapter(User::class.java) 7 val json = adapter.fromJsonValue(firstChild.value) 8 9 Log.d("json", json.toString()) 10 val user = json as User 11 12 Log.d("uid", user.uid) 13 Log.d("name", user.name) 14 Log.d("friends", user.friends.toString()) 15 16 user.friends.forEach { 17 array.add(it.value) 18 recyclerView.adapter.notifyItemChanged(array.size - 1) 19 } 20 21 } 22 23 override fun onCancelled(p0: DatabaseError?) { 24 Log.d("cancelled", "cancelled") 25 } 26})

投稿2018/01/20 02:45

sink66

総合スコア88

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問