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() で登録したリスナは解除する方法がないので、復旧できない。この場合はアプリを終了するしかない気がする。