概要
androidアプリ ツケ台帳 を作る際にFirebase realtimedatabaseを初めてさわったのですが、
特に詰まった部分を、備忘録かねて初心者的な目線でメモしてみます (スクリプト編)
アプリの解説、過去の投稿は→こちら
DB設計編はそのうち。
解決方法
Firebaseのリスナー内でcontextを参照する場合
this
だけでは取得できなかった。8行目のようにcontextの後に @○○Activity
の明示が必要。
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// xmlにて実装したListViewの取得
val listView = findViewById<ListView>(R.id.list_view)
// ArrayAdapterの生成
val adapter = DetailAdapter(this@DelDetailActivity, (mpostlist.tsuke?: mapOf()).toList())
// ListViewに、生成したAdapterを設定
listView.adapter = adapter
override fun onCancelled(databaseError: DatabaseError) {}
}database.child("fuga").addListenerForSingleValueEvent(postListener)
※コピペでやっているとハマりやすい
読み取り時のSnapshotの参照先
できるだけ狭い範囲を指定すべき。
後からセキュリティルールを定める時に困るし、一度に読むデータが多くなるのでユーザが増えると重くなる原因となる。
少なくともルート(下記画像ではdatabase
)を参照するのはやめる(セキュリティルールが全く設定できなくなる)。
NG例:database.addListenerForSingleValueEvent(Listener)
よい例:database.child("messages").addListenerForSingleValueEvent(Listener)
これをやるとルート直下のノードを複数読み込みたい場合に困るが、私の場合はリスナーを入れ子にした。下記の場合、3重になっている。その際、リスナー・スナップショットの名前は変えること。
(他にもっといい方法があるかもしれない。。)
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val postListener_teams = object : ValueEventListener {
override fun onDataChange(dataSnapshot_teams: DataSnapshot) {
val postListener_users = object : ValueEventListener {
override fun onDataChange(dataSnapshot_users: DataSnapshot) {
// 本文
}
override fun onCancelled(databaseError: DatabaseError) {}
}
database.child("Users").addListenerForSingleValueEvent(postListener_users)
}
override fun onCancelled(databaseError: DatabaseError) {}
}
database.child("Teams").child(teamKey).addListenerForSingleValueEvent(postListener_teams)
}
override fun onCancelled(databaseError: DatabaseError) {}
}
database.child("Posts").child(postKey).addListenerForSingleValueEvent(postListener)
リスナー内スクリプトの実行タイミング
リスナー内のスクリプトは、配置に関わらずリスナー以外のスクリプトがすべて実行された後に実行される。
例:onCreate内に 命令文1→リスナー内命令文→命令文2 の順番で記入されていた場合、実際には
命令文1→命令文2→リスナー内命令文 の順番で実行される。
Firebaseの読み取りは1回限りの場合もリスナーを使わないといけないので実行順に注意が必要。後から読み取りのリスナーを実装するとハマりやすい罠。
対策として、読み取りの命令文だけでなくその前後のスクリプトもまとめてリスナー内に入れていた。
リスナーの種類
特殊な事情がない限り
.addValueEventListener
でなく
addListenerForSingleValueEvent
(1回だけ実行して消えるリスナー)
を使うべき。リスナーが残っていて変な挙動をする例がよくある。特に初心者(私を含む)の場合はリスナーを活用した開発は難しいので.addValueEventListener
を原則使うようにしたほうが余計なトラブルがないだろうと思われる。
これはクエリを使ったリスナーでも同様。
TextViewなどの初期値
Firebaseだけの問題ではないかもしれないですが、DBから読み取って表示するデータは画面表示の際に読み込みのラグが発生するためxmlに初期値を入れておくとTextViewがチラついて見栄えが悪いです。