(210518 수정)
이번에는 실제로 채팅을 할 수 있게 채팅 기능을 만들어 보겠다.
앱을 만들 때 상당히 많이 사용하는 RecylerView 를 이용하니 잘 봐두면 좋을 것이다.
------------------------------------------------------------------------------------------------------
우선 채팅창의 화면은 activity_chat.xml이고 이 xml파일을 Inflation 시켜주는 클래스 파일은
ChatActivity.class 이고 이 클래스 부터 알아보자면
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
|
public class ChatActivity extends AppCompatActivity {
private static final String TAG = "ChatActivity";
private RecyclerView recyclerView;
MyAdapter adapter;
private RecyclerView.LayoutManager layoutManager; // 리사이클러뷰의 레이아웃을 정해줄 레이아웃 매니저
FirebaseDatabase database;
ArrayList<Chat> chatArrayList; // 모델(이메일과 텍스트)을 나열함
EditText edt;
Button btnSend;
String stEmail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
chatArrayList = new ArrayList<>(); // Chat 모델을 나열하는 ArrayList
database = FirebaseDatabase.getInstance();
stEmail = getIntent().getStringExtra("email"); // 인텐트로 MainActivity에서 입력된 이메일 값을 받아오는 문자열 값 email
edt = (EditText)findViewById(R.id.edt);
recyclerView = (RecyclerView)findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true); // 변경하지 않음 -> 항목의 높이가 바뀌지 않아야 비용이 적게 드므로 성능이 좋음
layoutManager = new LinearLayoutManager(this); // 리사이클러뷰의 레이아웃을 정해줄 레이아웃 매니저
recyclerView.setLayoutManager(layoutManager); // 리사이클러뷰에 리니어 레이아웃 매니저를 사용함
String[] myDataset = {"테스트1", "테스트2","테스트3", "테스트4"}; // myDataset에 다음과 같은 문자열 삽입
adapter = new MyAdapter(chatArrayList, stEmail); // chatArrayList를 어댑터로 연결, 회원의 이메일도 넘김
recyclerView.setAdapter(adapter); // 리사이클뷰에 어댑터를 설정
btnSend = (Button)findViewById(R.id.btnSend);
btnSend.setOnClickListener(new View.OnClickListener() { // 메시지 전송 버튼(화살표)을 누르면
@Override
public void onClick(View v) {
String stText = editText.getText().toString(); // 입력창에 입력한 문자가 stText에 담겨짐
editText.setText(""); // 입력창은 공백이됨
Calendar calendar = Calendar.getInstance(); // 캘린더 객체 인스턴스 calendar
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-dd-MMM HH:mm:ss"); // SimpleDataFormat 이라는 날짜와 시간을 출력하는 객체 생성, hh을 HH로 변경했더니 24시각제로 바뀜
String datetime = dateFormat.format(calendar.getTime()); // 캘린더 날짜시간 값을 가져와서 문자열인 datatime 으로 변환함
System.out.println(datetime); // 문자열 datetime 값 출력
DatabaseReference myRef = database.getReference("message").child(datetime); // 데이터베이스에 message 안에 자식으로 날짜인 datatime이 들어감
Hashtable<String, String> numbers // 해시테이블 객체 numbers 생성 후 안에 이메일과 입력한 문자가 들어감
= new Hashtable<String, String>();
numbers.put("email", stEmail);
numbers.put("text", stText);
myRef.setValue(numbers); // DB 객체에 numbers 객체가 설정됨
}
});
ChildEventListener childEventListener = new ChildEventListener() { // 현재 시간의 자식들인 이메일, 텍스트들을 담는 객체 생성
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { // 현재 시간의 자식들을 추가함
Log.d(TAG, "child를 추가합니다. :" + dataSnapshot.getKey());
// 리스너는 이벤트 발생 시점에 DB에서 지정된 위치에 있던 데이터를 포함하는
// DataSnapShot을 수신함. getValue()를 호출하면서 데이터의 자바 객체 표현이 반환됨
Chat chat = dataSnapshot.getValue(Chat.class);
// 모델인 Chat.class 에서 이메일이랑 텍스트를 가져와서 확인
String stEmail = chat.getEmail();
String stText = chat.getText();
Log.d(TAG, "이메일 가져오기 : " + stEmail);
Log.d(TAG, "텍스트 가져오기 : " + stText);
chatArrayList.add(chat); // Chat 모델을 추가하고
adapter.notifyDataSetChanged(); // 변경된다는 것을 어댑터에게 알려줌
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "Chile가 변경되었습니다. :" + dataSnapshot.getKey());
String commentKey = dataSnapshot.getKey();
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "CHild가 삭제되었습니다. :" + dataSnapshot.getKey());
String commentKey = dataSnapshot.getKey();
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "Child가 이동되었습니다. :" + dataSnapshot.getKey());
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "취소되었습니다. ", databaseError.toException());
}
};
DatabaseReference databaseReference = database.getReference("message"); // 데이터베이스에 message 라는 문자로 경로가 만들어짐
databaseReference.addChildEventListener(childEventListener);
}
}
|
cs@Override |
RecyclerView는 ListView와 비슷하지만
레이아웃을 레이아웃 매니저로 직접 선택할 수 있다는
차이점이 있다.
그리고 데이터를 저장하고 관리하는 Chat Model을 작성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class Chat {
String email;
String text;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
|
cs} |
Model은 디자인 패턴 중 하나이다.
필자가 디자인 패턴에 대해 아직 많이 미숙하기도 하고, 이 글에서 다룰 내용은 아니지만
Model에 대해서는 간략하게 말할 수 있을 것 같다.
Model은 쉽게 말해 어플리케이션의 정보, 즉 데이터를 말한다.
이번 채팅 기능에서의 데이터는 무엇을 말할까?
바로 이메일과 텍스트(채팅 메시지)를 말한다.
바로 이러한 Chat Model 데이터로
액티비티와 어댑터, 뷰와 상호작용을 할 수 있게 된다.
다음으로는 RecyclerView를 액티비티와 연결하고 설정하는
어댑터에 대해서 알아보자면
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
|
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private ArrayList<Chat> mDataset;
String stMyEmail = "";
public static class ViewHolder extends RecyclerView.ViewHolder { // 아이템 뷰를 저장하는 뷰홀더
private final TextView tvChat;
public ViewHolder(View view) {
super(view);
tvChat = (TextView) view.findViewById(R.id.tvChat); // 채팅문자가 입력될 텍스트뷰 찾기
}
public TextView getTextView() { // 채팅문자가 입력된 텍스트뷰 가져오기
return tvChat;
}
}
@Override
public int getItemViewType(int position) {
if(mDataset.get(position).email.equals(stMyEmail)) { // email과 stMyEmail과 같으면
return 1; // 내 메시지
} else { // stMyEail과 다르면
return 2; // 내 메시지가 아님
}
}
// Chat형 어레이 리스트 myDataset을 처음에 전역변수로 선언한 mDataset에 대입
public MyAdapter(ArrayList<Chat> myDataset, String stEmail) {
mDataset = myDataset;
this.stMyEmail = stEmail;
}
// 뷰홀더를 생성(레이아웃 생성)
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { // 아이템들을 어떻게 보여줄 것인가
View view = LayoutInflater.from(viewGroup.getContext()) // 상대방 메시지이면
.inflate(R.layout.left_text_view, viewGroup, false); // 말풍선이 왼쪽에서 나타나는 xml 파일 인플레이션
if(viewType == 1) { // 내 메시지이면
view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.right_text_view, viewGroup, false); // 말풍선이 오른쪽에서 나타나는 xml 파일 인플레이션
}
return new ViewHolder(view);
}
// 뷰홀더가 재활용될 때 실행
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
viewHolder.getTextView().setText(mDataset.get(position).getText());
}
@Override
public int getItemCount() {
return mDataset.size();
}
}
|
cs |
이런식으로 할 수 있다.
이렇게 해서
이메일과 패스워드를 입력해서 회원가입을 하고
로그인을 해서 채팅창으로 넘어가면
채팅을 자유롭게 할 수 있다.
피드백은 언제나 환영입니다.
'프로그래밍(programming) > 안드로이드(android)' 카테고리의 다른 글
안드로이드 스크롤뷰(ScrollView)로 화면 스크롤하기 (210423) (0) | 2021.04.23 |
---|---|
안드로이드 페이지 슬라이딩(Page Sliding) (210421) (0) | 2021.04.21 |
안드로이드 리사이클러뷰(RecyclerView) (210420) (2) | 2021.04.20 |
안드로이드 채팅 (2/3) - 채팅 화면 (210414) (0) | 2021.04.14 |
안드로이드 채팅 (1/3) - 로그인과 회원가입(210414) (0) | 2021.04.14 |