Created
May 11, 2019 14:33
-
-
Save wonsuc/90803dcf9e8179bcddac8bda62217e99 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package app.pwdr.firebase.manager; | |
import android.annotation.SuppressLint; | |
import android.util.Log; | |
import app.pwdr.firebase.model.FIRObject; | |
import com.google.android.gms.tasks.Task; | |
import com.google.android.gms.tasks.TaskCompletionSource; | |
import com.google.firebase.database.DataSnapshot; | |
import com.google.firebase.database.DatabaseError; | |
import com.google.firebase.database.DatabaseException; | |
import com.google.firebase.database.DatabaseReference; | |
import com.google.firebase.database.FirebaseDatabase; | |
import com.google.firebase.database.MutableData; | |
import com.google.firebase.database.Query; | |
import com.google.firebase.database.Transaction; | |
import com.google.firebase.database.ValueEventListener; | |
import java.util.Map; | |
public class DatabaseManager { | |
public static String TAG = "DatabaseManager"; | |
private DatabaseManager() { | |
} | |
public static FirebaseDatabase getDatabase() { | |
return FirebaseDatabase.getInstance(); | |
} | |
public static DatabaseReference getRef() { | |
return getDatabase().getReference(); | |
} | |
public static DatabaseReference getRef(String path) { | |
return getDatabase().getReference(path); | |
} | |
public static Task<Void> setValue(DatabaseReference ref, Object o) { | |
Log.i(TAG, "setValue:ref:" + (ref != null ? ref.toString() : "null")); | |
return ref.setValue(o); | |
} | |
public static Task<Void> updateChildren(Map<String, Object> map) { | |
Log.i(TAG, "updateChildren:map:" + map.toString()); | |
return getRef().updateChildren(map); | |
} | |
public static Task<Void> updateChildren(DatabaseReference ref, Map<String, Object> map) { | |
Log.i(TAG, "updateChildren:map:" + map.toString()); | |
return ref.updateChildren(map); | |
} | |
public static Task<DataSnapshot> getValue(DatabaseReference ref) { | |
final TaskCompletionSource<DataSnapshot> tcs = new TaskCompletionSource<>(); | |
Log.d(TAG, "getValue:ref:" + ref.toString()); | |
ref.addListenerForSingleValueEvent(new ValueEventListener() { | |
@Override | |
public void onDataChange(DataSnapshot dataSnapshot) { | |
Log.d(TAG, "getValue:onDataChange"); | |
tcs.setResult(dataSnapshot); | |
} | |
@Override | |
public void onCancelled(DatabaseError databaseError) { | |
Log.w(TAG, "getValue:onCancelled:" + databaseError.getMessage()); | |
tcs.setException(databaseError.toException()); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static <X extends FIRObject> X getValue(final DataSnapshot snapshot, final Class<X> aClass) { | |
// Log.i(TAG, "getValue"); | |
X firObject = snapshot.getValue(aClass); | |
firObject.setKey(snapshot.getKey()); | |
return firObject; | |
} | |
public static <X extends FIRObject> X getValue(MutableData mutableData, String key, final Class<X> aClass) { | |
// Log.i(TAG, "getValue"); | |
X firObject = mutableData.getValue(aClass); | |
if (firObject == null) return null; | |
firObject.setKey(key); | |
return firObject; | |
} | |
public static <X extends FIRObject> Task<X> getValue(final DatabaseReference ref, final Class<X> aClass) { | |
Log.d(TAG, "getValue:ref:" + ref.toString()); | |
final TaskCompletionSource<X> tcs = new TaskCompletionSource<>(); | |
ref.addListenerForSingleValueEvent(new ValueEventListener() { | |
@Override | |
public void onDataChange(DataSnapshot dataSnapshot) { | |
if (!dataSnapshot.exists()) { | |
NullDataException e = new NullDataException( | |
String.format("%s (%s)", "The value for the path is null.", ref.toString()) | |
); | |
Log.w(TAG, "getValue:onCancelled:error:" + e.getLocalizedMessage()); | |
tcs.setException(e); | |
return; | |
} | |
X x = dataSnapshot.getValue(aClass); | |
x.setKey(dataSnapshot.getKey()); | |
tcs.setResult(x); | |
} | |
@Override | |
public void onCancelled(DatabaseError databaseError) { | |
Log.w(TAG, "getValue:onCancelled:error:" + databaseError.getMessage()); | |
tcs.setException(databaseError.toException()); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static Task<DataSnapshot> getValue(final Query query) { | |
Log.i(TAG, "getValue:ref:" + query.getRef().toString()); | |
final TaskCompletionSource<DataSnapshot> tcs = new TaskCompletionSource<>(); | |
query.addListenerForSingleValueEvent(new ValueEventListener() { | |
@Override | |
public void onDataChange(DataSnapshot dataSnapshot) { | |
Log.d(TAG, "getValue:onDataChange"); | |
// 어차피 DataSnapshot를 반환하기 때문에 현재 패스의 존재 유무는 사용하는 곳에서 처리하도록 한다. | |
tcs.setResult(dataSnapshot); | |
} | |
@Override | |
public void onCancelled(DatabaseError databaseError) { | |
Log.w(TAG, "getValue:onCancelled", databaseError.toException()); | |
tcs.setException(databaseError.toException()); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static <X extends FIRObject> Task<X> getValue(final Query query, final Class<X> aClass) { | |
Log.i(TAG, "getValue:ref:" + query.toString()); | |
final TaskCompletionSource<X> tcs = new TaskCompletionSource<>(); | |
query.addListenerForSingleValueEvent(new ValueEventListener() { | |
@Override | |
public void onDataChange(DataSnapshot dataSnapshot) { | |
Log.d(TAG, "getValue:onDataChange:dataSnapshot:" + dataSnapshot.getValue()); | |
if (!dataSnapshot.exists()) { | |
NullDataException e = new NullDataException( | |
String.format("%s (%s)", "The Value for the path is null.", query.toString()) | |
); | |
Log.w(TAG, "getValue:onCancelled", e); | |
tcs.setException(e); | |
return; | |
} | |
tcs.setResult(getValue(dataSnapshot, aClass)); | |
} | |
@Override | |
public void onCancelled(DatabaseError databaseError) { | |
Log.w(TAG, "getValue:onCancelled", databaseError.toException()); | |
tcs.setException(databaseError.toException()); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static <X extends FIRObject> Task<X> getChildValue(final Query query, final Class<X> aClass) { | |
Log.i(TAG, "getValue:ref:" + query.toString()); | |
final TaskCompletionSource<X> tcs = new TaskCompletionSource<>(); | |
query.addListenerForSingleValueEvent(new ValueEventListener() { | |
@Override | |
public void onDataChange(DataSnapshot dataSnapshot) { | |
Log.d(TAG, "getValue:onDataChange:dataSnapshot:" + dataSnapshot.getValue()); | |
if (!dataSnapshot.exists()) { | |
NullDataException e = new NullDataException( | |
String.format("%s (%s)", "The Value for the path is null.", query.toString()) | |
); | |
Log.w(TAG, "getValue:onCancelled", e); | |
tcs.setException(e); | |
return; | |
} | |
tcs.setResult(getValue(dataSnapshot.getChildren().iterator().next(), aClass)); | |
} | |
@Override | |
public void onCancelled(DatabaseError databaseError) { | |
Log.w(TAG, "getValue:onCancelled", databaseError.toException()); | |
tcs.setException(databaseError.toException()); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static Task<String> getString(final DatabaseReference ref) { | |
Log.i(TAG, "getString:ref:" + ref.toString()); | |
final TaskCompletionSource<String> tcs = new TaskCompletionSource<>(); | |
ref.addListenerForSingleValueEvent(new ValueEventListener() { | |
@Override | |
public void onDataChange(DataSnapshot dataSnapshot) { | |
Log.d(TAG, "getString:onDataChange:dataSnapshot:" + dataSnapshot.getValue()); | |
if (!dataSnapshot.exists()) { | |
NullDataException e = new NullDataException( | |
String.format("%s (%s)", "The Value for the path is null.", ref.toString()) | |
); | |
Log.w(TAG, "getString:onCancelled:" + e.getMessage()); | |
tcs.setException(e); | |
return; | |
} | |
tcs.setResult(dataSnapshot.getValue(String.class)); | |
} | |
@Override | |
public void onCancelled(DatabaseError databaseError) { | |
Log.w(TAG, "getString:onCancelled:" + databaseError.toException().getMessage()); | |
tcs.setException(databaseError.toException()); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static Task<Boolean> getBoolean(final DatabaseReference ref) { | |
// Log.i(TAG, "getBoolean:ref:" + ref.toString()); | |
final TaskCompletionSource<Boolean> tcs = new TaskCompletionSource<>(); | |
ref.addListenerForSingleValueEvent(new ValueEventListener() { | |
@Override | |
public void onDataChange(DataSnapshot dataSnapshot) { | |
// Log.d(TAG, "getBoolean:onDataChange:dataSnapshot:" + dataSnapshot.getValue()); | |
if (!dataSnapshot.exists()) { | |
NullDataException e = new NullDataException( | |
String.format("%s (%s)", "The Value for the path is null.", ref.toString()) | |
); | |
Log.w(TAG, "getBoolean:onCancelled:error:" + e.getLocalizedMessage()); | |
tcs.setException(e); | |
return; | |
} | |
tcs.setResult(dataSnapshot.getValue(Boolean.class)); | |
} | |
@Override | |
public void onCancelled(DatabaseError databaseError) { | |
Log.w(TAG, "getBoolean:onCancelled:error:" + databaseError.getMessage()); | |
tcs.setException(databaseError.toException()); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static Task<Integer> getInteger(final DatabaseReference ref) { | |
// Log.i(TAG, "getInteger:ref:" + ref.toString()); | |
final TaskCompletionSource<Integer> tcs = new TaskCompletionSource<>(); | |
ref.addListenerForSingleValueEvent(new ValueEventListener() { | |
@Override | |
public void onDataChange(DataSnapshot dataSnapshot) { | |
// Log.d(TAG, "getInteger:onDataChange:dataSnapshot:" + dataSnapshot.getValue()); | |
if (!dataSnapshot.exists()) { | |
NullDataException e = new NullDataException(String.format("%s (%s)", "The Value for the path is null.", ref.toString())); | |
Log.w(TAG, "getInteger:onCancelled:error:" + e.getLocalizedMessage()); | |
tcs.setResult(0); | |
return; | |
} | |
tcs.setResult(dataSnapshot.getValue(Integer.class)); | |
} | |
@Override | |
public void onCancelled(DatabaseError databaseError) { | |
Log.w(TAG, "getInteger:onCancelled:error:" + databaseError.getMessage()); | |
tcs.setException(databaseError.toException()); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static Task<Void> runTransaction(DatabaseReference ref, final TransactionHandler handler) { | |
Log.i(TAG, "runTransaction"); | |
final TaskCompletionSource<Void> tcs = new TaskCompletionSource<>(); | |
ref.runTransaction(new Transaction.Handler() { | |
final String TAG = "Handler"; | |
@Override | |
public Transaction.Result doTransaction(MutableData mutableData) { | |
// 이유는 모르겠지만 최초에 null이 한번 반환되고 두번째에 제대로 된 값이 반환된다. | |
if (!mutableData.hasChildren()) return Transaction.success(mutableData); | |
Log.i(TAG, "doTransaction:mutableData:" + mutableData.toString()); | |
return handler.doTransaction(mutableData); | |
} | |
@Override | |
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) { | |
if (!b) { | |
tcs.setException(databaseError.toException()); | |
} | |
tcs.setResult(null); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public static Task<Void> runTransaction(DatabaseReference ref, final Transaction.Handler handler) { | |
final TaskCompletionSource<Void> tcs = new TaskCompletionSource<>(); | |
ref.runTransaction(new Transaction.Handler() { | |
@Override | |
public Transaction.Result doTransaction(MutableData mutableData) { | |
return handler.doTransaction(mutableData); | |
} | |
@Override | |
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) { | |
if (!b) { | |
tcs.setException(databaseError.toException()); | |
} | |
tcs.setResult(null); | |
} | |
}); | |
return tcs.getTask(); | |
} | |
public interface TransactionHandler { | |
Transaction.Result doTransaction(MutableData mutableData); | |
} | |
public static Task<Void> removeValue(DatabaseReference ref) { | |
Log.i(TAG, "removeValue"); | |
final TaskCompletionSource<Void> tcs = new TaskCompletionSource<>(); | |
ref.removeValue((databaseError, databaseReference) -> { | |
if (databaseError != null) { | |
Log.w(TAG, "removeValue:ERROR:" + databaseError.getMessage()); | |
tcs.setException(databaseError.toException()); | |
} | |
Log.d(TAG, "removeValue:SUCCESS"); | |
tcs.setResult(null); | |
}); | |
return tcs.getTask(); | |
} | |
public static String getPath(DatabaseReference ref) { | |
StringBuilder path = new StringBuilder("/" + ref.getKey()); | |
while (ref.getParent().getKey() != null) { | |
ref = ref.getParent(); | |
path.insert(0, "/" + ref.getKey()); | |
} | |
return path.toString(); | |
} | |
public static String getPath(DatabaseReference ref, String lastKey) { | |
return String.format("%s/%s", getPath(ref), lastKey); | |
} | |
public static boolean isLastDataReached(DataSnapshot snapshot, int requestedAmount) { | |
int count = (int) snapshot.getChildrenCount(); | |
boolean isReached = count < requestedAmount; | |
Log.d(TAG, "isLastDataReached:count:" + count + "|requestedLimit:" + requestedAmount + "|result:" + isReached); | |
return isReached; | |
} | |
public static class NullDataException extends DatabaseException { | |
@SuppressLint("RestrictedApi") | |
public NullDataException(String detailMessage) { | |
super(detailMessage); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package app.pwdr.firebase.model; | |
import androidx.annotation.Nullable; | |
import com.google.firebase.database.Exclude; | |
import com.google.firebase.database.IgnoreExtraProperties; | |
import java.io.Serializable; | |
@IgnoreExtraProperties | |
public class FIRObject implements Serializable { | |
@Exclude | |
@Nullable | |
String key; | |
@Exclude | |
@Nullable | |
public String getKey() { | |
return key; | |
} | |
@Exclude | |
public void setKey(@Nullable String key) { | |
this.key = key; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment