앞서서 Android기반 Firebase 실시간 데이터베이스(Realtime database) 예제를 실행하고 테스트 하는 것을 정리하였고,

이번에는 예제 소스를 이해하는 데 도움이 될 수 있도록 파일 구조, 데이터 베이스 구조등을 정리한다.

여기에서는 Firebase에 대하여 정리하지 않고, Android 프로그래밍 중심으로 정리한다.

예제를 이해하는데에는 Firebase 실시간 데이터베이스에 알면 조금 더 쉽게 이해할 수 있을 것이다.

관련 문서를 한번 읽어 보길 바란다.


1. Firebase realtime database 실행과 테스트

2. Firebase realtime database 구조와 프로그램 구조

3. Firebase realtime database 코드

4. Firebase realtime database를 Cloud Firestore로


Android Studio에서 패키지 구조를 살펴 보면 다음 그림의 좌측과 같이 제법 많은 파일(클래스)이 있는 것을 볼 수 있다.


각 파일을 열어서 보려면 익숙하지 않아서 이해하기 어렵고,

다음 그림과 같이 각 파일을 기능으로 매핑 시켜서 정리하면 보다 쉽게 이해 할 수 있다.

예제는 4개의 Activity와 3개의 Fragment로 구성되어 있다.

최신글(RecentPostsFragment), 내가 작성한 글(MyPostsFragment), 내가 작성한 인기글(MyTopPostsFragment)은 Fragment로 작성되어

메인 화면 (MainActivity)의 Tablayout에 사용되었다.

메인 화면 (MainActivity)에서 플로팅 버튼(글쓰기)을 선택하면 글작성(NewPostActivity) Activity가 실행된다.

작성된 글 리스트( 3개의 Fragment)에서 하나의 글을 선택하면 글 읽기(PostDetailActivity)가 실행되고,

댓글(comments)을 작성할 수 있다.


조금 더 자세히 정리하면,

최신글(RecentPostsFragment), 내가 작성한 글(MyPostsFragment), 내가 작성한 인기글(MyTopPostsFragment)은 동일한 화면 구조를 가지고 있다.

출력되는 데이터가

최신글은 전체 글 리스트를 시간 순으로 출력한 것이고,

내가 작성한 글은 내가 작성한 글 리스트를 출력한 것이다.

내가 작성한 인기글은 내가 작성한 글 중에서 인기 있는(별을 많이 받은) 글 리스트를 출력한 것이다.

모두 사용자가 작성한 글 리스트를 출력하는 것으로,

Firebase 실시간 데이터베이스에서 가져오는 데이터만 다르고 모든 것이 동일하다.

즉, 조회 조건만 다를 뿐이다.


따라서, 하나의 Fragment에 모든 기능을 구현하고 (PostListFragment)

각각의 파일에서는 이 기능을 상속 받아서 데이터를 가져오는 코드만 적절하게 작성하여 구현했다.


부모 Fragment인 PostListFragment에서 주어진 데이터를 적절한 리스트 디자인(fragment_all_posts)에 맞추어 (ViewHoder) 출력하게 작성한다.


그리고, 데이터를 가져오는 getQuery 메소드를 추상적(abstract)으로 선언하였다.

public abstract class PostListFragment extends Fragment {

    ~~ 생략 ~~
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
    ~~ 생략 ~~
        Query postsQuery = getQuery(mDatabase);

    ~~ 생략 ~~

    public abstract Query getQuery(DatabaseReference databaseReference);

}

추상적으로 선언된 getQuery메소드를 onActivityCreated 에서 호출하도록 작성하였다.

즉, Activity가 생성될때 필요한 데이터를 가지고 오도록 getQuery를 호출한다.


PostListFragment를 상속받은(extends) 각각의 자식 Fragment에서는 getQuery메소드만 필요에 맞게끔 구현한다(Override).

최신글

 (RecentPostsFragment)

public class RecentPostsFragment extends PostListFragment {
    @Override
    public Query getQuery(DatabaseReference databaseReference) {
        Query recentPostsQuery = databaseReference.child("posts")
                .limitToFirst(100);
        return recentPostsQuery;
    }
}

내가 작성한 글

(MyPostsFragment)

  public class MyPostsFragment extends PostListFragment {
    @Override
    public Query getQuery(DatabaseReference databaseReference) {
        return databaseReference.child("user-posts")
                .child(getUid());
    }
}

 내가 작성한 인기 글

(MyTopPostsFragment)

 public class MyTopPostsFragment extends PostListFragment {
    @Override
    public Query getQuery(DatabaseReference databaseReference) {
        String myUserId = getUid();
        Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
                .orderByChild("starCount");
        return myTopPostsQuery;
    }
}


4의 Activity도 하나의 클래스(BaseActivity)에서 상속받아 구현하였다.


Activity들의 부모로 사용되는 BaseActivity는 Fragment처럼 복잡하게 구성하지 않고 다음 코드와 같이 단순하다.

BaseActivity.java

어떤 처리에 대한 진행 상태를 나타내는 ProgressDialog의 설정을 미리 작성해 두고

보이게(showProgressDialog)하거나 [라인5], 숨기게(hideProgressDialog) [라인15]하는 메소드를 가지고 있다.

또, 모든 Activity에서 사용하는 사용자 UID을 가져오는 기능을 getUid 메소드로 구현해 두었다 [라인21].

즉, 많이 사용하는 기능을 부모에 구현해두고, 자식에서 사용하는 구조로 작성된 것이다.


저장되는 데이터 구조를 정리하면 다음과 같이 4개의 스카마로 작성되었다.


Fireabse 콘솔로 접근해 보면,

사용자(users), 사용자별 글(user-posts), 작성된 글(posts), 코멘트(post-comments)가 생성되어 데이터가 저장된 것을 볼 수 있다.

사용자별 작성 글(user-posts)과 전체 작성 글(posts)은 동일한 구조와 데이터를 가진다.

사용자별 작성 글(user-posts)은 한 사용자가 작성한 모든 글을 저장하는 스키마이고,

전체 작성 글(posts)은 사용자에 관계없이, 사이트내의 모든 글을 저장하는 스키마이다.

사용자별 글(user-posts)은 사용자가 작성한 글이기 때문에 사용자 UID 별로 작성된 글(posts)을 저장한다.


사용자별 작성 글(user-posts)과 전체 작성 글(posts)에 있는 stars 필드는 각각의 글에 별(start)을 누른 사용자들의 uid를 저장한다.

어떤 글에 대하여 내가 별을 선택한 경우 다시 해제하는 기능을 구현하는데 사용한다.

어떤 글에 대하여 내가 별을 선택하면 stars 필드에 내 uid가 추가된다.

이후에 다시 그 글을 읽으면, 내가 별을 선택했다는 의미로 별에 색이 채워져서 표시된다.

즉, 해당 글의 stars 필드에 내 uid가 있으면 표시를 한다.

다시 별을 클릭하면(취소하면) stars 필드에서 내 uid를 제거하고 채워진 별이 외곽선만 남게 된다.

좋아요(별)를 선택했다가 취소하는 기능을 구현하는 것이다.


코멘트(post-comments)는 전체 작성글 번호마다 각각의 코멘트가 작성된 순서데로 저장되고

사용자(users)에는 이메일과 이름이 저장되어 있다.

Firebase에서 제공되는 인증(Authentication) 기능이 사용자를 관리하는 기능이지만,

다른 사용자에 대한 정보에 접근을 관리자(admin)으로 제한하기 때문에 사용자의 로그인 기능으로만 사용하고,

글 리스트에서 작성자 이름을 출력하는 등의 다른 사용자에 대한 정보를 가져오는 것은 별도의 사용자(users) 스키마에 저장해서 구현한다.


이상으로 구글에서 제공하는 Firebase realtime database 기반의 Android 예제를 정리하였다.

모바일에서 많이 사용되는 서비스를 구현한 것으로 제법 재미있게 작성되었다.

다만, 작성한 글을 삭제하거나 수정할 수 있는 기능이 구현되어 있지 않다.

최근에 작성한 코멘트가 위에 있는 것이(Descending) 좋겠지만 마지막에(Ascending) 출력된다.

정리된 내용을 기초 개념으로 하여 미 구현된 기능을 구현하거나 보강하면 실력향상에 도움이 될 것 같다.


[Tip] 사용자 입력 값 체크하기

SignInActivity의 validateForm 함수는 개발에 유용한 코드가 사용되었다.

private boolean validateForm() {
boolean result = true;
if (TextUtils.isEmpty(mEmailField.getText().toString())) {
mEmailField.setError("Required");
result = false;
} else {
mEmailField.setError(null);
}

if (TextUtils.isEmpty(mPasswordField.getText().toString())) {
mPasswordField.setError("Required");
result = false;
} else {
mPasswordField.setError(null);
}

return result;
}

사용자가 입력한 값(getText)이 비었는지 확인하고 (TextUtils.isEmpty)

비었을 경우 다음과 같이 입력하라고 알려주는(setError) 기능이 사용되었다.





+ Recent posts