Firebase 자식 노드 제거 및 참조하기
안드로이드 스튜디오에서 기억해둘 것이 있어서 정리해둔다.
모든 Firebase 세팅이 끝나고 FirebaseManageEngine.class를 다음과 같이 작성한다.
public class FirebaseManageEngine {
static private FirebaseDatabase LocalDB = FirebaseDatabase.getInstance();
static private DatabaseReference LocalDBref = FirebaseDatabase.getInstance().getReference();
public FirebaseManageEngine(){
}
public static void RenewDatabaseReference(){
LocalDBref = FirebaseDatabase.getInstance().getReference();
}
public static void RenewDatabase(){
LocalDB = FirebaseDatabase.getInstance();
}
//getter & setter
public static DatabaseReference getFreshLocalDBref(){
RenewDatabaseReference();
return LocalDBref;
}
public static FirebaseDatabase getFreshLocalDB(){
RenewDatabase();
return LocalDB;
}
}
LocalDBref는 최상위 루트 Layer의 reference를 뜻함.
예를 들어 위와 같은 노드 체계를 갖춘 DB에서 transactions 중 특정 조건(timestamp의 date 값이 어떠한 값보다 적은)을 만족하는 노드들을 모두 삭제하려고 할 때, 다음과 같은 방식을 사용하면 된다.
(불행하게도 모두 지워서 transaction이 하나밖에 없다.. 여러 개 있다고 가정하자.)
위의 과정이 어떤 버튼의 클릭 시 실행되게 하려면 그냥 아래의 코드를 onClickListener()에 넣어버리면 된다.
String stamp = "190...(생략)";
try {
final long standTamp = Global.transactionDateFormat.parse(stamp).getTime();
final DatabaseReference myref = FirebaseManageEngine.getFreshLocalDB().getReference(Global.rootName+"/transactions");
myref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot data : dataSnapshot.getChildren()){
String str = data.child("timestamp").getValue().toString();
try {
long time = Global.transactionDateFormat.parse(str).getTime();
if(time <= standTamp) {
myref.child(data.getKey()).removeValue();
new LogEngine().sendLog("remove this");
}
}catch(ParseException e){
e.printStackTrace();
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}catch(ParseException e){
e.printStackTrace();
}
DataSnapShot의 dataEntry를 추출하여 나온 data 하나하나는 object 취급되어 getValue(SampleClass.class);
이런 식으로 받아올 수 있긴 한데(Mapping이 필요함), 나는 변환이 잘 안되는 것 같다.
for 문 내의 data가 각 transaction 항목들을 가지고 있다. (toString으로 출력하면 JSON 형식으로 출력됨)
해당 data들은 child() 함수로 element들을 JSON처럼 파고들 수 있는데, 들어가서 getValue() 호출 시 원하는 값을 얻어올 수 있다.
String str = data.child("timestamp").getValue().toString();
이와 같이 getKey()를 통해 키를 얻고 reference 재정의할 필요 없이 바로 접근할 수 있다는 것이다.
해당 데이터들이 RecyclerView 같은 list 형식에 속해 있다면,
DatabaseReference myref = FirebaseManageEngine.getFreshLocalDB().getReference(Global.rootName+"/transactions");
myref.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String s) {
//do something..
}
@Override
public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
String stamp = dataSnapshot.getValue(MoneyTransaction.class).timestamp;
Iterator<MoneyTransaction> iter = transactions.iterator();
while(iter.hasNext()){
MoneyTransaction trans = iter.next();
if(trans.timestamp.equals(stamp))
iter.remove();
}
mAdapter.notifyDataSetChanged();
}
@Override
public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
위와 같은 형식으로 해당 리스트에 iterator를 적용하여 remove를 실행해준다.
iterator 없이 일반 loop를 돌린다면 ConcurrentModificationException이 발생할 것이다.