Firebase를 이용한 안드로이드 스튜디오 Chatting
안드로이드 스튜디오

Firebase를 이용한 안드로이드 스튜디오 Chatting

유튜브 센치한 개발자님의 소스 코드로 공부를 시작했다. 

www.youtube.com/watch?v=2yrO-mDCl4U&list=PLva6rQOdsvQXdSBN1r2mEt_tqES6NjKKj&index=25

github.com/sentiLabs/sentilab_youtube/blob/master/Android/java/app/src/main/java/com/kplo/samplesenti/ChatActivity.java

 

sentiLabs/sentilab_youtube

Contribute to sentiLabs/sentilab_youtube development by creating an account on GitHub.

github.com

사용자의 입장에서 단계를 나누어서 한번 설명해 보자면, 

1단계: A사용자가 채팅을 입력을 한다. 

2단계: 그 데이터가 firebase real data db에 저장이 된다. 

3단계: 데이터를 firebase에서 불러와서 B 사용자가 있는 채팅 화면에 보여준다. 

이러한 과정을 계속해서 반복하는것이 채팅이다. 

 

먼저 크게 과정을 나누어보면, 
1. recyclerView - 반복
2. 디비 내용을 넣는다
3. 상대방폰에 채팅 내용이 보임 - get

이렇게 세단계이다. 

 

0. firebase 와 realdatabase 세팅:

0-1.tools-> firebase

0-2.realtime data base-> save and retrieve data

0-3. 

1번과 2번의 과정을 따라하면,

1번을 통해 내 firebase에 앱을 추가하고, 

2번을 통해 필요한 dependency를 자동으로 추가한다. 

 

0-4.

마지막으로 파이어베이스 홈페이지에 로그인후 콘솔로가서 만든 프로젝트를 선택하고, 세팅에 들어가서, 내 프로젝트 세팅을 누르고, 

그 프로젝트의 google-services.json 파일을 다운로드 후, 안드로이드 스튜디오 프로젝트 안에 app이라는 폴더 안으로 넣어준다. 

stackoverflow.com/questions/33866061/error-file-google-services-json-is-missing-from-module-root-folder-the-google/50173745

 

Error "File google-services.json is missing from module root folder. The Google Services Plugin cannot function without it"

I updated my project to the latest Play services classpath 'com.google.gms:google-services:1.5.0-beta2'. I am also using the latest version of playservices in my app.gradle file as: compile 'com.g...

stackoverflow.com

 

 

firebase.google.com/docs/android/setup?authuser=0

 

Android 프로젝트에 Firebase 추가

기본 요건 Android 스튜디오를 설치하거나 최신 버전으로 업데이트합니다. Android 앱이 다음을 충족하는지 확인합니다. API 수준 16(Jelly Bean) 이상 타겟팅 Gradle 4.1 이상 사용 앱을 실행할 기기 또는 ��

firebase.google.com

더 해결이 안되는 부분이 있다면, firebase 공식 문서를 참고해서 사용법을 익히길 추천한다. 

 

1. 채팅에서 전달 받을 내용을 클래스로 만들어 주려고 한다. 

ChatData 라는 클래스를 하나 만들어서, 채팅에서 전달받을 내용을 담는 객체를 먼저 만든다.

package com.example.chatting;

/**
 * Created by KPlo on 2018. 11. 3..
 */

public class ChatData {
    private String msg;
    private String nickname;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
}

 

2. 리사이클러 뷰를 세팅해주기 위해서, 리사이클러 뷰 어답터를 만든다. 

이때 리사이클러 뷰는 채팅 내용의 개수만큼 반복적으로 스크롤 되게 보여주기 위해서 만든다. 

package com.example.chatting;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

/**
 * Created by KPlo on 2018. 10. 28..
 */

public class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.MyViewHolder> {
    private List<ChatData> mDataset;
    private String myNickName;
    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public static class MyViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public TextView TextView_nickname;
        public TextView TextView_msg;
        public View rootView;
        public MyViewHolder(View v) {
            super(v);
            TextView_nickname = v.findViewById(R.id.TextView_nickname);
            TextView_msg = v.findViewById(R.id.TextView_msg);
            rootView = v;
        }


    }

    // Provide a suitable constructor (depends on the kind of dataset)
    public ChatAdapter(List<ChatData> myDataset, Context context, String myNickName) {
        //{"1","2"}
        mDataset = myDataset;
        this.myNickName = myNickName;
    }

    //data setting
    // Create new views (invoked by the layout manager)
    @Override
    public ChatAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
                                                     int viewType) {
        // create a new view
        LinearLayout v = (LinearLayout) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.row_chat, parent, false);

        MyViewHolder vh = new MyViewHolder(v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        ChatData chat = mDataset.get(position);

        holder.TextView_nickname.setText(chat.getNickname());
        holder.TextView_msg.setText(chat.getMsg());

        if(chat.getNickname().equals(this.myNickName)) {
            holder.TextView_msg.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_END);
            holder.TextView_nickname.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_END);
        }
        else {
            holder.TextView_msg.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
            holder.TextView_nickname.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
        }

    }


    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {

        //삼항 연산자
        return mDataset == null ? 0 :  mDataset.size();
    }

    public ChatData getChat(int position) {
        return mDataset != null ? mDataset.get(position) : null;
    }

    public void addChat(ChatData chat) {
        mDataset.add(chat);
        notifyItemInserted(mDataset.size()-1); //갱신
    }


}

 

3.리사이클러 뷰의 layout과 chatting의 레이아웃을 만든다. 

나는 리사이클러 뷰 즉, 채팅에 뜨는 데이터 하나 하나의 레이아웃은 row_chat이라는 xml에, 

chatting 화면의 레이아웃은 activity_main.xml에 만들었다. 

 

3-1.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="1"
    >

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:orientation="horizontal"
        android:weightSum="1">
        <EditText
            android:id="@+id/EditText_chat"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"/>
        <Button
            android:id="@+id/Button_send"
            android:text="SEND"
            android:layout_width="80dp"
            android:layout_height="match_parent" />
    </LinearLayout>

</LinearLayout>

 

3-2.row_chat.xml 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <!-- A CardView that contains a TextView -->
    <TextView
        android:textSize="12sp"
        android:id="@+id/TextView_nickname"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <TextView
        android:textSize="20sp"
        android:id="@+id/TextView_msg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

 

4.main activity에서 리사이클러뷰 연결해주고, firebase 통신하는 코드

package com.example.chatting;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    public  RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private List<ChatData> chatList;
    private String nick = "nick1"; // ID 전달 받아서 넣기

    private EditText EditText_chat;
    private Button Button_send;
    private DatabaseReference myRef;

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

        Button_send = findViewById(R.id.Button_send);
        EditText_chat = findViewById(R.id.EditText_chat);

        Button_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String msg = EditText_chat.getText().toString(); //msg

                if(msg != null) {
                    ChatData chat = new ChatData();
                    chat.setNickname(nick);
                    chat.setMsg(msg);
                    myRef.push().setValue(chat);
                }

            }
        });

        mRecyclerView = findViewById(R.id.my_recycler_view);
        mRecyclerView.setHasFixedSize(true);
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        chatList = new ArrayList<>();
        mAdapter = new ChatAdapter(chatList, MainActivity.this, nick);

        mRecyclerView.setAdapter(mAdapter);

        // Write a message to the database
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        myRef = database.getReference();

        //caution!!!

        myRef.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
                Log.d("CHATCHAT", dataSnapshot.getValue().toString());
                ChatData chat = dataSnapshot.getValue(ChatData.class);
                ((ChatAdapter) mAdapter).addChat(chat);
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

            }

            @Override
            public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });



    }
}

'안드로이드 스튜디오' 카테고리의 다른 글

안스 디버깅 노트  (0) 2021.05.11
Backend 레퍼런스 정리  (0) 2021.05.11
Frontend 레퍼런스 정리  (0) 2021.05.11
Flask - 안드로이드 스튜디오 통신  (1) 2020.07.22
OK HTTP 통신  (0) 2020.07.15