Polyglot's language & programming story.

Firebase3 ) Firebase Realtime 데이터베이스를 이용해서 데이터 송수신하기 본문

Programming/AndroidProgramming

Firebase3 ) Firebase Realtime 데이터베이스를 이용해서 데이터 송수신하기

Polyglot 2018. 7. 6. 23:06

Firebase Realtime 데이터베이스를 사용해서 데이터 송수신하기

이번에도 Udacity의 예제를 이용해서 Firebase Realtime Database를 사용해서 데이터 송수신을 하는 방법을 살펴봅시다.

Database 송수신 클래스를 알아보기

먼저 FirebaseDatabase 클래스와 DatabaseReference 객체를 알 필요가 있습니다.

1
2
private DatabaseReference mDatabaseReference;   // 데이터베이스의 주소를 저장합니다.
private FirebaseDatabase mFirebaseDatabase;     // 데이터베이스에 접근할 수 있는 진입점 클래스입니다.

FirebaseDatabase 클래스로 실시간 데이터베이스를 접근 할 수 있고 DatabaseReference 클래스는 데이터의 주소를 저장합니다.

곧 다음과 같이 사용합니다.

1
2
mFirebaseDatabase = FirebaseDatabase.getInstance();     // 현재 데이터 베이스를 접근할 수 있는 진입점 받기
mDatabaseReference = mFirebaseDatabase.getReference().child("messages");        // 메시지 child로 이동.

mFirebaseDatabase.getReference() 메소드는 데이터베이스의 루트 폴더 주소 값을 반환하는 메소드입니다.

송신을 하려면 mDatabaseReference객체를 이용해서 setValue()메소드와 push()메소드를 이용합니다. push() 메소드는 pushId를 생성시켜주는 함수이고. setValue()는 JSON 객체로 지정된 위치에 데이터를 저장하는 메소드입니다.

1
2
FriendlyMessage mFriendlyMessage = new FriendlyMessage(mMessageEditText.getText().toString(), mUsername, null); // 텍스트를 받고 FriendlyMessage 객체에 형식에 맞춰 넣습니다.
mDatabaseReference.push().setValue(mFriendlyMessage);  // 루트 주소로 부터 pushId를 설정하고 그 아래에 mFriendlyMessage객체를 Serializable (직렬화) 시켜서 저장합니다.

위 코드는 텍스트를 메시지 클래스에 형식에 맞춰 저장을 시키고 지정한 주소에 직렬화시켜 JSON 객체로 변환시킵니다.

또한 데이터베이스 안에 있는 데이터가 변할 때 수신을 위해서 리스너가 필요합니다. 리스너를 선언하고 정의한 뒤 mDatabaseReference 객체에 리스너를 등록을 해야합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private ChildEventListener mChildEventListener;
 
mChildEventListener = new ChildEventListener() {
            // 데이터가 추가 되었을 때.
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                //dataSnapshot은 위 메소드가 호출 될때의 data이다.
                FriendlyMessage mFriendlyMessage = dataSnapshot.getValue(FriendlyMessage.class);
                mMessageAdapter.add(mFriendlyMessage);
            }
 
            //데이터가 변화되었을 때
            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
            }
 
            //데이터가 제거되었을때
            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
            }
 
            // 데이터가 파이어베이스 DB 리스트 위치 변경되었을때
            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {
 
            }
 
            // DB처리중 오류가 발생했을 때
            @Override
            public void onCancelled(DatabaseError databaseError) {
            }
        };

ChildEventListener는 5개의 메소드를 오버라이딩을 해야합니다.

  1. onChildAdded : 파이어베이스 데이터베이스의 데이터가 추가되었을 때 자동 호출
  2. onChildChanged : 파이어베이스 데이터베이스의 데이터가 수정되었을 때 자동 호출
  3. onChildRemoved : 파이어베이스 데이터베이스의 데이터가 삭제되었을 때 자동 호출
  4. onChildMoved : 파이어베이스 데이터베이스의 데이터의 리스트 위치가 변했을 때 자동 호출
  5. onCancelled : 파이어베이스 데이터베이스 통신 실패등 오류가 발생했을 때 자동 호출
1
mDatabaseReference.addChildEventListener(mChildEventListener);

또한 이렇게 만든 리스너를 addChildEventListener를 통해서 등록 해주어야 됩니다.

전체코드를 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
public class MainActivity extends AppCompatActivity {
 
    private static final String TAG = "MainActivity";
 
    private static final int RC_SIGN_IN = 100;
 
    public static final String ANONYMOUS = "anonymous";
    public static final int DEFAULT_MSG_LENGTH_LIMIT = 1000;
 
    private ListView mMessageListView;
    private MessageAdapter mMessageAdapter;
    private ProgressBar mProgressBar;
    private ImageButton mPhotoPickerButton;
    private EditText mMessageEditText;
    private Button mSendButton;
 
    private String mUsername;
 
    private DatabaseReference mDatabaseReference;
    private FirebaseDatabase mFirebaseDatabase;
    private ChildEventListener mChildEventListener;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        mFirebaseDatabase = FirebaseDatabase.getInstance();     // 현재 데이터 베이스를 접근할 수 있는 진입점 받기
        mDatabaseReference = mFirebaseDatabase.getReference().child("messages");        // 메시지 child로 이동.
 
        mUsername = ANONYMOUS;
 
        // Initialize references to views
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        mMessageListView = (ListView) findViewById(R.id.messageListView);
        mPhotoPickerButton = (ImageButton) findViewById(R.id.photoPickerButton);
        mMessageEditText = (EditText) findViewById(R.id.messageEditText);
        mSendButton = (Button) findViewById(R.id.sendButton);
 
        // Initialize message ListView and its adapter
        List<FriendlyMessage> friendlyMessages = new ArrayList<>();
        mMessageAdapter = new MessageAdapter(this, R.layout.item_message, friendlyMessages);
        mMessageListView.setAdapter(mMessageAdapter);
 
        // Initialize progress bar
        mProgressBar.setVisibility(ProgressBar.INVISIBLE);
 
        // ImagePickerButton shows an image picker to upload a image for a message
        mPhotoPickerButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // TODO: Fire an intent to show an image picker
            }
        });
 
        // Enable Send button when there's text to send
        mMessageEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }
 
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (charSequence.toString().trim().length() > 0) {
                    mSendButton.setEnabled(true);
                } else {
                    mSendButton.setEnabled(false);
                }
            }
 
            @Override
            public void afterTextChanged(Editable editable) {
            }
        });
        mMessageEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(DEFAULT_MSG_LENGTH_LIMIT)});
 
        // Send button sends a message and clears the EditText
        mSendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // TODO: Send messages on click
                FriendlyMessage mFriendlyMessage = new FriendlyMessage(mMessageEditText.getText().toString(), mUsername, null);
                mDatabaseReference.push().setValue(mFriendlyMessage);
                // Clear input box
                mMessageEditText.setText("");
            }
        });
 
        mChildEventListener = new ChildEventListener() {
            // 데이터가 추가 되었을 때.
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                //dataSnapshot은 위 메소드가 호출 될때의 data이다.
                FriendlyMessage mFriendlyMessage = dataSnapshot.getValue(FriendlyMessage.class);
                mMessageAdapter.add(mFriendlyMessage);
            }
 
            //데이터가 변화되었을 때
            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
            }
 
            //데이터가 제거되었을때
            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
            }
 
            // 데이터가 파이어베이스 DB 리스트 위치 변경되었을때
            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {
 
            }
 
            // DB처리중 오류가 발생했을 댸
            @Override
            public void onCancelled(DatabaseError databaseError) {
            }
        };
        mDatabaseReference.addChildEventListener(mChildEventListener);
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return super.onOptionsItemSelected(item);
    }
}

위 전체 코드는 MainActivity.java 입니다. 앞에서 논했던, 데이터 송수신까지 구현을 했습니다. 하지만 이대로는 작동이 잘 안될 것입니다.

왜냐하면 파이어베이스에서는 인증이 안된 사용자가 보내는 데이터를 걸러서 받기 때문입니다. 따라서 아직 위 예제에서는 사용자 인증을 하지 않았으니, 사용자인증을 무시하도록 설정해주어야됩니다.

파이어베이스 홈페이지에 들어가 데이터베이스 탭에서 규칙을 누릅니다.


위 규칙에서 "auth != null" 이 부분 때문에 데이터가 받아지지 않는 것인데. 이를 true로 바꿉니다 (실제로 앱을 출시한다면 이러한 방법을 하면 절대로 안됩니다.)


그대로 게시를 누르고 다시 앱에서 데이터를 보내고 잘 들어오고 리스트에 잘 보여지는지 확인하시면 됩니다.


잘 표시가 되는 것을 확인 할 수가 있습니다.

다음 포스팅에서는 권한과 Firebase UI를 이용하여 권한 인증을 알아보도록 하겠습니다.

Comments