アイデアは単純です:ValueEventListenerを、いくつかのversionタグにバインドします。このタグは、データを更新してその状態を変更するSingleValueEventコールバックでリクエストを作成します。
と仮定、私はUser
オブジェクトを持っていると私は、タイムスタンプの内容とver
プロパティを追加するバージョン管理のために:
users : {
id : {
name : 'Mr. Anderson',
ver : '<timestamp>'
}
}
データ状態を確認するために私がenum State
、interface StateIndicatable
、interface OnStateChangeListener
を紹介:
enum State{ INIT, LOADING, LOADED, FAILED }
interface OnStateChangeListener{
void stateChanged(State newState);
}
interface StateIndicatable{
State getState();
void setOnStateChangeListener(OnStateChangeListener listener);
void clearOnStateChangeListener();
}
私はwouldn User
モデルを変更したいと思います。ビュー/プレゼンテーション/ビューモデルのレベルに存在するラッパーを使用します:
私は、任意のバージョン管理モデルを中心に抽象ラッパーを作成したいと思います。ここでは
abstract class FirebaseVersionedModelWrapper<M> implements StateIndicatable{
int version;
protected WeakReference<M> modelRef;
State state;
OnStateChangeListener onStateChangeListener;
DatabaseReference verRef;
FirebaseVersionedModelWrapper(M model, String firebasePath, OnStateChangeListener onStateChangeListener){
this.modelRef = new WeakReference(model);
this.state = State.INIT;
this.onStateChangeListener = onStateChangeListener;
verRef = FirebaseDatabase.getInstance().getReference(firebasePath + "/ver");
verRef.keepSynced(true);
verRef.addValueEventListener(
new OnValueEventListener(){
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(modelRef.get()==null){
verRef.removeEventListener(this);
return;
}
if(dataSnapshot.hasChild("ver"){
if(dataSnapshot.child("ver").getValue(Integer.class) != version){
requestUpdate();
}
}
else
setState(State.FAILED);
}
@Override
public void onCancelled(DatabaseError databaseError) {
if(modelRef.get()==null){
verRef.removeEventListener(this);
return;
}
setState(State.FAILED);
}
}
);
}
private void requestUpdate(){
setState(State.LOADING);
DatabaseReference ref = FirebaseDatabase
.getInstance
.getReference(firebasePath);
ref.keepSynced(true);
ref.addListenerForSingleValueEvent(
new OnValueEventListener(){
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
M model = modelRef.get();
if (model==null) return;
if(dataSnapshot.hasChild("ver")){
version = dataSnapshot.child("ver").getValue(Integer.class);
setFields(model, dataSnapshot);
setState(State.LOADED);
}
else{
setState(State.FAILED);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
setState(State.FAILED);
}
}
);
}
private void setState(State newState){
if (this.state == newState) return;
this.state = newState;
if (onStateChangeListener != null)
onStateChangeListener.stateChanged(newState);
}
@Override
public State getState(){
return this.state;
}
@Override
public void setOnStateChangeListener(OnStateChangeListener listener){
this.onStateChangeListener = listener;
}
@Override
public void clearOnStateChangeListener(){
this.onStateChangeListener = null;
}
protected abstract void setFields(M model, DataSnapshot dataSnapshot);
}
DatabaseReference#keepSynced(true)
は、データパス上の要求が新鮮なデータを返すことを確認するために呼ばれています。これは論議的なアプローチであり、今私の練習では完全には確認されていません。
その後、私はUserWrapper
にUser
をラップ:
class UserWrapper extends FirebaseVersionedModelWrapper<User>{
FirebasedUser(User userModel, String userPath, OnStateChangeListener listener){
super(userModel, userPath, listener);
}
@Override
void setFields(User model, DataSnapshot dataSnapshot){
// setting values for model
}
}
、最終的に私がOnStateChangeListenerコールバックにラッパーとバインド表示ルーチンをインスタンス化することができます
まあ
User user = new User();
UserWrapper wrapper = new UserWrapper(
user,
new OnStateChangeListener(){
@Override
void stateChanged(State newState){
if(newState == State.LOADED){
showUserDetails();
}
else if(newState == State.FAILD){
showErrorState();
}
else{
showLoadingIndicator();
}
}
}
);
、私が言ったように、任意の意見やここに掲載されている代替ソリューションは大変ありがとう!
コードはメモリからタイプされており、間違いの可能性があります。