TL;博士
是否可以将Firebase read and write operations后面的所有ObservableMap
都隐藏为Facade Pattern?
因此,我们要做的就是:
User oldUser = map.put(user);
User newUser = map.get(primaryKey);
完整问题
根据Firebase documentation,要写一个值,我必须通过a
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可能吗? 最佳答案
TL;博士
我将ObservableArrayMap
和ChildEventListener
合并为FirebaseArrayMap
。
一个可用的FirebaseUI-Android示例可用here。现在您要做的就是:
// 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);
记住要在
OnMapChangedCallback
和onResume
中取消注册onPause
,以避免由ChildEventListener
远程更新引起的内存泄漏。欺诈
首先,我们需要为
Map
创建一个同义词库接口,即: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();
}
此接口将由
FirebaseArrayMap
实现,并返回与Map
返回的值相同的值。这些方法类似于
put
,putAll
和get
,但是它们不是返回值,而是返回带有那些值(或异常)的Tasks
。例: @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
我们创建一个抽象
FirebaseArrayMap
来扩展ObservableArrayMap
并实现ChildEventListener
和CRUD
。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;
}
ChildEventListener
将使用超级方法,将ObservableArrayMap
转换为本地缓存。因此,成功完成写操作(或发生远程更改)时,
ChildEventListener
将自动更新我们的Map
@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());
}
合约
为了不破坏
CRUD
合约,需要Map
接口。例如,当在给定位置插入新值时,put
返回先前的值,但是此操作现在是异步的。对于写操作,这里的黑客使用
CRUD
进行非阻塞操作,并使用Map
进行阻塞操作: @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;
}
}
数据绑定
免费,现在您的Android Data Binding也有
Map
:@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());
}
}
请记住在
onResume
和onPause
中取消注册回调,以免由于ChildEventListener
更新导致的内存泄漏。