본문 바로가기
Project/안드로이드 프로젝트(HomingBird)

Android Studio, JAVA, Google Firebase] 한번의 매서드로, 세 개의 쿼리를 처리하기

by 김마리님 2020. 11. 10.

결과 :

다음 결과는 위에서부터 차례로 .whereEqualTo("code", keyword) // .whereEqualTo("email", keyword) // .whereEqualTo("username", keyword)를 한 매서드에서 처리한 결과값입니다. (정확히는 완료를 담당하는 매서드까지 두 개 입니다.)

파이어베이스를 다루다보면 문제 하나에 부딪힙니다. 바로.. 검색기능이 동기적으로 처리되지 않고 비동기적으로 처리된다는 점입니다. 그래서 세 검색 쿼리를 절차지향적으로 하나씩 처리하는 것은 좀 힘들죠. 그렇기에 하나에 주목해야합니다. 데이터베이스는 늘 새로운 인스턴스를 만들어서 처리한다는 점입니다. 즉, 세 쿼리가 다 따로 놀게 됩니다. 그렇기 때문에 완료되는 것을 알려줄 일종의 콜백장치가 필요하게 됩니다.

즉, 필요한 것은

1. 쿼리가 3개 모인 한 매서드

2. 결과가 완료됐음을 알려줄 무언가.

3. 그 결과를 받아 최종적인 호출을 실행할 함수

먼저 전역으로 세 개의 값을 선언해줍니다. (뭐.......... 굳이 전역으로 안해도 될 것 같긴 해요.)

그리고 결과를 저장할 해시맵도 선언해줍시다.

    private boolean isCode = false;
    private boolean isEmail = false;
    private boolean isUsername = false;
    private HashMap<String, Object> hashMap = new HashMap<>();

그리고, 본격적인 매서드를 적어봅시다.

    private void findFriend(String keyword) {
        db.collection("user")
                .whereEqualTo("code", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            hashMap.put("email", documentSnapshot.getData().get("email"));
                            String username = (String) documentSnapshot.getData().get("username");
                            if(username == null){
                                hashMap.put("username", "설정된 닉네임이 없습니다.");
                            } else {
                                hashMap.put("username", documentSnapshot.getData().get("username"));
                            }
                            hashMap.put("code", documentSnapshot.getData().get("code"));
                        }
                    }
                    DlogUtil.d(TAG, hashMap);
                    isCode = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.printStackTrace());

        db.collection("user")
                .whereEqualTo("email", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            hashMap.put("email", documentSnapshot.getData().get("email"));
                            String username = (String) documentSnapshot.getData().get("username");
                            if(username == null){
                                hashMap.put("username", "설정된 닉네임이 없습니다.");
                            } else {
                                hashMap.put("username", documentSnapshot.getData().get("username"));
                            }
                            hashMap.put("code", documentSnapshot.getData().get("code"));
                        }
                    }
                    DlogUtil.d(TAG, hashMap);
                    isEmail = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.printStackTrace());

        db.collection("user")
                .whereEqualTo("username", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            hashMap.put("email", documentSnapshot.getData().get("email"));
                            String username = (String) documentSnapshot.getData().get("username");
                            if(username == null){
                                hashMap.put("username", "설정된 닉네임이 없습니다.");
                            } else {
                                hashMap.put("username", documentSnapshot.getData().get("username"));
                            }
                            hashMap.put("code", documentSnapshot.getData().get("code"));
                        }
                    }
                    DlogUtil.d(TAG, hashMap);
                    isUsername = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.printStackTrace());
    }

해시맵은 세 쿼리가 다른 인스턴스에서 돌기 때문에 이를 합쳐줄 것이 필요합니다. 따라서, 쿼리가 실행될 구문 밖에서 처리해줘야 합니다.

여기서 주목할 점은, task.isSuccessful() 구문의 마지막입니다. for문으로 모든 데이터를 가져오면, 마지막으로 앞서 선언해두었던 상태 표시용 변수(isCode, isEmail, isUsername)를 변경합니다. 그리고 이 것을 최종적으로 해결해줄 마지막 콜백함수를 부릅니다.

    private void setRecycler(){
        if(isCode && isEmail && isUsername){
            DlogUtil.d(TAG, "으앙 : " + hashMap);
        }
    }

이 콜백 함수는 모든 함수가 마무리 되어 true가 된다면 작동할 것입니다. 따라서 이 함수가 마치 콜백함수처럼 돌아가게 되지요. 아직은 안 적었지만 여기서 최종적으로 해시맵을 모아 리사이클러뷰로 처리하게 될 것 같습니다.

이걸 쭉 연결해보면 이런 코드가 나오겠네요. 코드가 좀 길어 접었습니다.

 

더보기
package com.mary.homingbird.findFriend;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import com.mary.homingbird.R;
import com.mary.homingbird.util.DlogUtil;

import java.util.HashMap;

public class FindFriendActivity extends AppCompatActivity {

    private static final String TAG = "FindFriendActivity";

    private ImageView imageViewSearch;
    private EditText editTextSearch;

    private FirebaseFirestore db;

    private boolean isCode = false;
    private boolean isEmail = false;
    private boolean isUsername = false;
    private HashMap<String, Object> hashMap = new HashMap<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_find_friend);

        findView();
        initGoogle();
        setListener();
    }

    private void initGoogle() {
        db = FirebaseFirestore.getInstance();
    }

    private void findView() {
        imageViewSearch = findViewById(R.id.imageViewSearch);
        editTextSearch = findViewById(R.id.editTextSearch);
    }

    private void setListener() {
        imageViewSearch.setOnClickListener(v -> {
            String keyword = editTextSearch.getText().toString().trim();
            findFriend(keyword);
        });
    }

    private void findFriend(String keyword) {
        db.collection("user")
                .whereEqualTo("code", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            hashMap.put("email", documentSnapshot.getData().get("email"));
                            String username = (String) documentSnapshot.getData().get("username");
                            if(username == null){
                                hashMap.put("username", "설정된 닉네임이 없습니다.");
                            } else {
                                hashMap.put("username", documentSnapshot.getData().get("username"));
                            }
                            hashMap.put("code", documentSnapshot.getData().get("code"));
                        }
                    }
                    DlogUtil.d(TAG, hashMap);
                    isCode = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.printStackTrace());

        db.collection("user")
                .whereEqualTo("email", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            hashMap.put("email", documentSnapshot.getData().get("email"));
                            String username = (String) documentSnapshot.getData().get("username");
                            if(username == null){
                                hashMap.put("username", "설정된 닉네임이 없습니다.");
                            } else {
                                hashMap.put("username", documentSnapshot.getData().get("username"));
                            }
                            hashMap.put("code", documentSnapshot.getData().get("code"));
                        }
                    }
                    DlogUtil.d(TAG, hashMap);
                    isEmail = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.printStackTrace());

        db.collection("user")
                .whereEqualTo("username", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            hashMap.put("email", documentSnapshot.getData().get("email"));
                            String username = (String) documentSnapshot.getData().get("username");
                            if(username == null){
                                hashMap.put("username", "설정된 닉네임이 없습니다.");
                            } else {
                                hashMap.put("username", documentSnapshot.getData().get("username"));
                            }
                            hashMap.put("code", documentSnapshot.getData().get("code"));
                        }
                    }
                    DlogUtil.d(TAG, hashMap);
                    isUsername = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.printStackTrace());
    }


    private void setRecycler(){
        if(isCode && isEmail && isUsername){
            DlogUtil.d(TAG, "으앙 : " + hashMap);
        }
    }

}

 

 

--20.11.10 수정--

이 상태로 검색을 두 번 하게 될 경우, 이전에 기록이 남습니다. 이걸 원하신다면 계속 사용하셔도 무방하지만 원래.. 검색이 그렇지 않잖아요 ^^..

그렇다고 함수 내에서 ArrayList나 HashMap을 재선언하면 OutOfBoundException 오류를 발생시킵니다. 왜 그러냐면.. 첫 검색으로 true가 된 상태에서 먼저 완료된 인스턴스가 비어있다면 이것으로 결과를 출력해버리기 때문입니다. 그래서 수정한 쿼리 매서드는 다음과 같습니다.

 

 

쿼리를 시작하기 전에 초기화를 진행하는거죠.

(중간에 저는 .. 리사이클러뷰를 쓸거라 ArrayList로 바꿨습니다.)

 

    private void findFriend(String keyword) {

        userBeans = new ArrayList<>();

        isCode = false;
        isEmail = false;
        isUsername = false;

        db.collection("user")
                .whereEqualTo("code", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            userBeans.add(documentSnapshot.toObject(UserBean.class));
                        }
                    }
                    isCode = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.printStackTrace());

        db.collection("user")
                .whereEqualTo("email", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            userBeans.add(documentSnapshot.toObject(UserBean.class));
                        }
                    }
                    isEmail = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.printStackTrace());

        db.collection("user")
                .whereEqualTo("username", keyword)
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
                            userBeans.add(documentSnapshot.toObject(UserBean.class));
                        }
                    }
                    isUsername = true;
                    setRecycler();
                })
                .addOnFailureListener(e -> e.
                        printStackTrace());
    }

 

 

 

반응형