Skip to content

Instantly share code, notes, and snippets.

@remcomokveld
Created July 10, 2016 22:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save remcomokveld/09b111e54dfc9cd8c0fc9a4d9c3bd63b to your computer and use it in GitHub Desktop.
Save remcomokveld/09b111e54dfc9cd8c0fc9a4d9c3bd63b to your computer and use it in GitHub Desktop.
FirebaseLoaders
package nl.remcomokveld.firebaseloaders;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.content.Loader;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.ValueEventListener;
public class FirebaseItemLoader<Type> extends Loader<Type> implements ValueEventListener {
private final DatabaseReference databaseReference;
private final SnapshotAdapter<Type> snapshotAdapter;
public FirebaseItemLoader(@NonNull Context context,
@NonNull DatabaseReference databaseReference,
@NonNull SnapshotAdapter<Type> snapshotAdapter) {
super(context);
this.databaseReference = databaseReference;
this.snapshotAdapter = snapshotAdapter;
}
@Override
protected void onStartLoading() {
super.onStartLoading();
databaseReference.addValueEventListener(this);
}
@Override
protected void onStopLoading() {
super.onStopLoading();
databaseReference.removeEventListener(this);
}
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
deliverResult(snapshotAdapter.adapt(dataSnapshot));
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
}
package nl.remcomokveld.firebaseloaders;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.Loader;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FirebaseListLoader<Type> extends Loader<List<Type>> implements ChildEventListener {
private final SnapshotAdapter<Type> snapshotAdapter;
private final DatabaseReference mDatabaseReference;
/** Both a List and a HashMap are used for storing references to the result because
* the list allows keeping the data sorted and the Map allows O(n) access times when updating
* or deleting data
*/
List<Item> mItems = new ArrayList<>();
Map<String, Item> mItemMap = new HashMap<>();
public FirebaseListLoader(@NonNull Context context,
@NonNull DatabaseReference databaseReference,
@NonNull SnapshotAdapter<Type> snapshotAdapter) {
super(context);
this.snapshotAdapter = snapshotAdapter;
this.mDatabaseReference = databaseReference;
}
@Override
protected void onStartLoading() {
super.onStartLoading();
mDatabaseReference.addChildEventListener(this);
}
@Override
protected void onStopLoading() {
super.onStopLoading();
mDatabaseReference.removeEventListener(this);
}
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (mItemMap.containsKey(dataSnapshot.getKey())) return;
Type appWrapper = snapshotAdapter.adapt(dataSnapshot);
Item newItem = new Item(dataSnapshot.getKey(), appWrapper, s);
mItems.add(newItem);
mItemMap.put(newItem.key, newItem);
updateResult();
}
private void updateResult() {
Collections.sort(mItems);
ArrayList<Type> types = new ArrayList<>(mItems.size());
for (Item item : mItems) {
types.add(item.value);
}
deliverResult(types);
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
mItemMap.get(dataSnapshot.getKey()).value = snapshotAdapter.adapt(dataSnapshot);
updateResult();
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Item item = mItemMap.get(dataSnapshot.getKey());
mItems.remove(item);
updateResult();
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
Item item = mItemMap.get(dataSnapshot.getKey());
item.previousKey = s;
updateResult();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
private class Item implements Comparable<Item> {
@NonNull private String key;
@Nullable private String previousKey;
@NonNull private Type value;
public Item(@NonNull String key, @NonNull Type value, @Nullable String previousKey) {
this.key = key;
this.previousKey = previousKey;
this.value = value;
}
@Override
public int compareTo(@NonNull Item item) {
if (previousKey == null || key.equals(item.previousKey)) return -1;
if (item.key.equals(previousKey)) return 1;
return 0;
}
}
}
private static class AppSnapshotAdapter implements SnapshotAdapter<SampleValueObject> {
@Override
public SampleValueObject adapt(DataSnapshot dataSnapshot) {
return new SampleValueObject(dataSnapshot);
}
}
private static class SampleValueObject {
private final DataSnapshot dataSnapshot;
public SampleValueObject(DataSnapshot dataSnapshot) {
this.dataSnapshot = dataSnapshot;
}
@Override
public String getId() {
return dataSnapshot.getKey();
}
@Override
public String getName() {
return dataSnapshot.child("name").getValue(String.class);
}
}
package nl.remcomokveld.firebaseloaders;
import com.google.firebase.database.DataSnapshot;
public interface SnapshotAdapter<Type> {
Type adapt(DataSnapshot dataSnapshot);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment