Firebase RTDB で同じパスに対する Listen 時の注意
modified: 2018-02-20
使用したライブラリは以下のバージョン。
implementation "com.google.firebase:firebase-core:11.8.0"
implementation "com.google.firebase:firebase-database:11.8.0"
概要
データベース(のパス)に読み取りアクセス権がない場合、登録したリスナの onCancelled()
が呼ばれるが、orderBy を指定してリスナを設定したあと、同じパスに orderBy を指定せずに別のリスナを設定すると、orderBy を指定したリスナには onCancelled()
がコールバックされるが、指定しないリスナの onCancelled()
は呼ばれない。
バグのようだったので、いずれ直るかもしれません。
検証
ログを出力するだけの LogValueEventListener
、LogChildEventListener
を用意し、以下のようなコードを書いてみる。
val ref = FirebaseDatabase.getInstance().getReference("test")
ref.orderByKey().addListenerForSingleValueEvent(LogValueEventListener("single-order"))
ref.addListenerForSingleValueEvent(LogValueEventListener("single"))
ref.orderByKey().addValueEventListener(LogValueEventListener("value-order"))
ref.addValueEventListener(LogValueEventListener("value"))
ref.orderByKey().addChildEventListener(LogChildEventListener("child-order"))
ref.addChildEventListener(LogChildEventListener("child"))
同じパスに6つのリスナを登録しているが、onCancelled()
が呼ばれたのは orderByKey()
を指定した3つのみ。orderByKey()
を指定しなかったリスナの onCancelled()
は呼ばれなかった。
先頭を orderByKey()
なしにしてみる。(2行めと3行めを入れ替え)
val ref = FirebaseDatabase.getInstance().getReference("test")
ref.addListenerForSingleValueEvent(LogValueEventListener("single"))
ref.orderByKey().addListenerForSingleValueEvent(LogValueEventListener("single-order"))
ref.orderByKey().addValueEventListener(LogValueEventListener("value-order"))
ref.addValueEventListener(LogValueEventListener("value"))
ref.orderByKey().addChildEventListener(LogChildEventListener("child-order"))
ref.addChildEventListener(LogChildEventListener("child"))
この場合はすべてのリスナで onCancelled()
が呼ばれた。
あとからパーミッションがなくなった場合
addValueEventListener()
または addChildEventListener()
で登録したリスナに対しては、onDataChanged()
などのイベントが通知された後で、パーミッションがなくなった場合も onCancelled()
が呼ばれる。
しかし addListenerForSingleValueEvent()
はワンショットなので、 onDataChanged()
が呼ばれた後は onCancelled()
は呼ばれない。
最初に登録したリスナが orderBy ありの addListenerForSingleValueEvent()
で、その他が orderBy なしだけの場合、
val ref = FirebaseDatabase.getInstance().getReference("test")
ref.orderByKey().addListenerForSingleValueEvent(LogValueEventListener("single-order"))
ref.addValueEventListener(LogValueEventListener("value"))
ref.addChildEventListener(LogChildEventListener("child"))
いずれのリスナの onCancelled()
も呼ばれず、パーミッションエラーになったことに気づくことができなかった。
その後
パーミッションエラーになった後、さらにリスナを登録した場合、もう orderBy ありだろうがなしだろうが何も通知されなくなってしまった。
登録済みのリスナをすべて removeEventListener()
で解除したらこの現象は直った。
しかし、addListenerForSingleValueEvent()
で登録したリスナは解除する方法がないので、復旧できない。この場合はアプリを終了するしかない気がする。