是否可以隐藏Firebase read and write operations ObservableMap
后面的所有Facade Pattern?
所以我们所要做的就是:
User oldUser = map.put(user);
User newUser = map.get(primaryKey);
根据Firebase documentation,为了写一个值,我必须通过DatabaseReference
定义资源路径并设置一个值。
例如,如果我们有一个User
纯文本对象,我们会将它设置为:
mDatabase.child("users")
.push()
.setValue(user);
为了阅读整个users
树,我们必须实现ChildEventListener
。只要新用户成为树的一部分,就会通过onChildAdded
:
@Override
public void onChildChanged (DataSnapshot snapshot, String previousChildName) {
Log.i(TAG, snapshot.getValue(User.class));
}
最后,为了阅读特定用户,我们使用ValueEventListener
:
mDatabase.child("users")
.child(primaryKey)
.setValue(user)
.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
Log.i(TAG, snapshot.getValue(User.class));
}
@Override
public void onCancelled(DatabaseError error) {
Log.w(TAG, "loadPost:onCancelled", error.getMessage());
}
});
那么可以使用ObservableMap
作为Facade Pattern,隐藏所有Firebase read and write operations吗?
答案 0 :(得分:1)
我将ObservableArrayMap
和ChildEventListener
合并为FirebaseArrayMap
。
可以使用FirebaseUI-Android有效的here示例OnMapChangedCallback
。现在你所要做的就是:
// Remote updates immediately send you your view
map.addOnMapChangedCallback(mUserChangedCallback);
// Non blocking operation to update database
map.create(user);
// Local up-to-date cache
User user = map.get(primaryKey);
请记住(取消)在onResume
和onPause
中注册ChildEventListener
,以避免Map
远程更新导致的内存泄漏。
首先我们需要为FirebaseArrayMap
创建词库接口,即:
public interface CRUD<K, V> {
Task<V> create(V value);
Task<V> create(K key, V value);
Task<Void> createAll(SimpleArrayMap<? extends K, ? extends V> array);
Task<Void> createAll(Map<? extends K, ? extends V> map);
V read(K key);
Task<V> delete(K key);
Task<Void> free();
}
这些方法类似于putAll
,get
和Tasks
,但不是返回值,而是返回FirebaseArrayMap
这些值(或例外)。例如:
@Override
public Task<Void> createAll(Map<? extends K, ? extends V> map) {
Collection<Task<V>> tasks = new ArrayList<>(map.size());
for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
tasks.add(create(entry.getKey(), entry.getValue()));
}
return Tasks.whenAll(tasks);
}
@Override
public V read(K key) {
return get(key);
}
@Override
public Task<V> delete(K key) {
final V oldValue = get(key);
final Continuation<Void, V> onDelete = new Continuation<Void, V>() {
@Override
public V then(@NonNull Task<Void> task) throws Exception {
task.getResult();
return oldValue;
}
};
return mDatabaseReference.child(key.toString())
.setValue(null)
.continueWith(onDelete);
}
我们创建了一个展开ObservableArrayMap
的摘要ChildEventListener
并实施了CRUD
和ChildEventListener
。
public abstract class FirebaseArrayMap<K extends Object, V> extends
ObservableArrayMap<K, V> implements ChildEventListener, CRUD<K, V> {
private final DatabaseReference mDatabaseReference;
public abstract Class<V> getType();
public FirebaseArrayMap(@NonNull DatabaseReference databaseReference) {
mDatabaseReference = databaseReference;
}
ObservableArrayMap
将使用超级方法,将ChildEventListener
转换为本地缓存。
因此,当成功完成写入操作(或发生远程更改)时,Map
将自动更新我们的CRUD
@Override
public void onCancelled(DatabaseError error) {
Log.e(TAG, error.getMessage(), error.toException());
}
@Override
public void onChildAdded(DataSnapshot snapshot, String previousChildName) {
if (snapshot.exists()) {
super.put((K) snapshot.getKey(), snapshot.getValue(getType()));
}
}
@Override
public void onChildChanged(DataSnapshot snapshot, String previousChildName) {
super.put((K)snapshot.getKey(), snapshot.getValue(getType()));
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
super.put((K)snapshot.getKey(), snapshot.getValue(getType()));
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
super.remove(dataSnapshot.getKey());
}
Map
接口是必需的,以便不违反put
合同。例如,CRUD
在给定位置插入新值时返回先前的值,但此操作现在异步。
对于编写操作,此处的hack使用Map
进行非阻止,使用Android Data Binding进行阻止操作:
@Override
@WorkerThread
public V put(K key, V value) {
try {
return Tasks.await(create(key, value));
} catch (ExecutionException e) {
return null;
} catch (InterruptedException e) {
return null;
}
}
@Override
protected onCreate() {
mUserMap = new UserArrayMap();
mChangedCallback = new OnUserMapChanged();
}
@Override
protected void onResume() {
super.onResume();
mUserMap.addOnMapChangedCallback(mChangedCallback);
}
@Override
protected void onPause() {
mUserMap.removeOnMapChangedCallback(mChangedCallback);
super.onPause();
}
和
static class OnUserMapChanged extends OnMapChangedCallback<FirebaseArrayMap<String, User>, String, User> {
@Override
public void onMapChanged(FirebaseArrayMap<String, User> sender, String key) {
Log.e(TAG, key);
Log.e(TAG, sender.get(key).toString());
}
}
请记住(取消)在onPause
和ChildEventListener
中注册您的回调,以避免{{3}}次更新导致的内存泄漏。