Android_채팅앱 만들어보기

홍성채·2022년 4월 27일
0

Android

목록 보기
22/27

채팅앱 만들어보기

Firebase 데이터 구조


각 클래스의 역할

MainActivity

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class LoginActivity extends AppCompatActivity {
    EditText UserPw;
    EditText UserId;
    Button btnlog;
    String[] userIdList = {"smhrd","mj"};
    String[] userPwList = {"4321","1234"};
   
   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        UserId = findViewById(R.id.edtUserId);
        UserPw = findViewById(R.id.edtUserPw);
        btnlog = findViewById(R.id.btnLogin);

            btnlog.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    String id = UserId.getText().toString();
                    String pw = UserPw.getText().toString();
                    for(int i =0; i<userIdList.length; i++){

                        if(id.equals(userIdList[i]) && pw.equals(userPwList[i])){
                            Intent intent = new Intent(LoginActivity.this,ChatActivity.class);
                            intent.putExtra("id",id);

                            startActivity(intent);
                            break;
                        }
                        if(i==userIdList.length-1){
                            Toast.makeText(LoginActivity.this,
                                    "다시 로그인해주세요",
                                    Toast.LENGTH_SHORT).show();
                        }

                    }
                }
            });
        }
    }

activity_login.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".LoginActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="139dp"
        android:layout_marginTop="116dp"
        android:layout_marginEnd="139dp"
        android:text="SM Talk App"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/edtUserId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="101dp"
        android:layout_marginTop="68dp"
        android:layout_marginEnd="101dp"
        android:ems="10"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <EditText
        android:id="@+id/edtUserPw"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="101dp"
        android:layout_marginTop="56dp"
        android:layout_marginEnd="101dp"
        android:ems="10"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/edtUserId" />

    <Button
        android:id="@+id/btnLogin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="112dp"
        android:text="로그인"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/edtUserPw"
        app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>

chatActivity

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

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ScrollView;

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.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

public class ChatActivity extends AppCompatActivity {
    ListView chatList;
    ChatAdapter adapter;
    ArrayList<ChatVO> list;

    EditText edtMsg;
    Button btnSend;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat2);
        chatList = findViewById(R.id.ChatList);
        list = new ArrayList<ChatVO>();
        edtMsg = findViewById(R.id.edtMsg);
        btnSend = findViewById(R.id.btnSend);

        String currentId = getIntent().getStringExtra("id");
        Log.d("ChatAcitivity","현재 로그인 한 id는 "+currentId);

        FirebaseDatabase database = FirebaseDatabase.getInstance();
        DatabaseReference myRef = database.getReference("talk");
        
        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Calendar cal = Calendar.getInstance();
                SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
                String time = sdf.format(cal.getTime());

                String msg = edtMsg.getText().toString();
                myRef.push().setValue(new ChatVO(R.drawable.ic_launcher_background,
                        currentId,
                        msg,
                        time));
            }
        });
        myRef.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
                ChatVO vo = snapshot.getValue(ChatVO.class);//자동으로 데이터 갯수만큼 읽어옴
                list.add(vo);
                adapter.notifyDataSetChanged();//자동으로 반영
            }

            @Override
            public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {

            }

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

            }

            @Override
            public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {

            }

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

            }
        });

        adapter = new ChatAdapter(ChatActivity.this,
                R.layout.chat_item,
                list,
                currentId);
        chatList.setAdapter((adapter));
        Intent intent = getIntent();
    }
}
코드 해석
 FirebaseDatabase database = FirebaseDatabase.getInstance();
 DatabaseReference myRef = database.getReference("talk");

해당 부분은 파이어베이스 데이터베이스 객체를 생성하고 데이터베이스 내에 있는 데이터를 참조하는 객체를 생성한다.

  btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Calendar cal = Calendar.getInstance();
                SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
                String time = sdf.format(cal.getTime());

                String msg = edtMsg.getText().toString();
                myRef.push().setValue(new ChatVO(R.drawable.ic_launcher_background,
                        currentId,
                        msg,
                        time));
            }
        });

메세지 입력 후 버튼 클릭 시 입력한 데이터를 불러와 db에 저장시킨다. 시간을 입력하기 위해
SimpleDateFormat와 Calendar 함수를 이용했고 시간 형식은 인터넷을 참고하면 된다.

   myRef.push().setValue(new ChatVO(R.drawable.ic_launcher_background,
                       currentId,
                       msg,
                       time));

해당 부분이 만들어놓은 VO 형식을 db에 저장시킨다.

       myRef.addChildEventListener(new ChildEventListener() {
           @Override
           public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
               ChatVO vo = snapshot.getValue(ChatVO.class);//자동으로 데이터 갯수만큼 읽어옴
               list.add(vo);
               adapter.notifyDataSetChanged();//자동으로 반영
           }

           @Override
           public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {

           }

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

           }

           @Override
           public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {

           }

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

           }
       });

파이어베이스 데이터베이스에 저장된 데이터를 가져온 후 list객체에 저장

ChatAdapter

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;

public class ChatAdapter extends BaseAdapter {
    Context context;
    int layout;
    ArrayList<ChatVO> list;
    LayoutInflater inflater; // xml-> view로 변환
    String currentId;

    public ChatAdapter(Context context, int layout, ArrayList<ChatVO> list, String currentId) {
        this.context = context;
        this.layout = layout;
        this.list = list;
        this.currentId = currentId;
        inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE); // 절대 변하지 않음
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return list.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int position, View view, ViewGroup viewGroup) { //i는 위치, view - layout의 정보, viewGroup - 부모 레이아웃(Listview)
        if(view == null){
            //view는 chat_item.xml 정보를 가진 객체
            view = inflater.inflate(layout,viewGroup,false); // 보여줄 layout 정보를 viewGroup(listview)에 합친다라고 생각
        }

        ImageView imgOther= view.findViewById(R.id.imgOther);
        TextView tvOtherNm = view.findViewById(R.id.tvOtherNm);
        TextView tvOtherMsg = view.findViewById(R.id.tvOtherMsg);
        TextView tvOtherTime = view.findViewById(R.id.tvOtherTime);
        TextView tvMyMsg = view.findViewById(R.id.tvMyMsg);
        TextView tvMyTime = view.findViewById(R.id.tvMyTime);

        ChatVO vo = list.get(position);

       
        if(list.get(position).getName().equals(currentId)){
            imgOther.setVisibility(View.INVISIBLE);
            tvOtherNm.setVisibility(View.INVISIBLE);
            tvOtherMsg.setVisibility(View.INVISIBLE);
            tvOtherTime.setVisibility(View.INVISIBLE);

            tvMyMsg.setVisibility(View.VISIBLE);
            tvMyTime.setVisibility(View.VISIBLE);

            tvMyMsg.setText(vo.getMsg());
            tvMyTime.setText(vo.getTime());
        }else{
            imgOther.setVisibility(View.VISIBLE);
            tvOtherNm.setVisibility(View.VISIBLE);
            tvOtherMsg.setVisibility(View.VISIBLE);
            tvOtherTime.setVisibility(View.VISIBLE);

            tvMyMsg.setVisibility(View.INVISIBLE);
            tvMyTime.setVisibility(View.INVISIBLE);

            imgOther.setImageResource(vo.getImgId());
            tvOtherNm.setText(vo.getName());
            tvOtherMsg.setText(vo.getMsg());
            tvOtherTime.setText(vo.getTime());
        }




        return view;
    }
}
코드 해석
if(list.get(position).getName().equals(currentId)){
            imgOther.setVisibility(View.INVISIBLE);
            tvOtherNm.setVisibility(View.INVISIBLE);
            tvOtherMsg.setVisibility(View.INVISIBLE);
            tvOtherTime.setVisibility(View.INVISIBLE);

            tvMyMsg.setVisibility(View.VISIBLE);
            tvMyTime.setVisibility(View.VISIBLE);

            tvMyMsg.setText(vo.getMsg());
            tvMyTime.setText(vo.getTime());
        }else{
            imgOther.setVisibility(View.VISIBLE);
            tvOtherNm.setVisibility(View.VISIBLE);
            tvOtherMsg.setVisibility(View.VISIBLE);
            tvOtherTime.setVisibility(View.VISIBLE);

            tvMyMsg.setVisibility(View.INVISIBLE);
            tvMyTime.setVisibility(View.INVISIBLE);

            imgOther.setImageResource(vo.getImgId());
            tvOtherNm.setText(vo.getName());
            tvOtherMsg.setText(vo.getMsg());
            tvOtherTime.setText(vo.getTime());
        }

현재 로그인한 아이디 판단
상대방 id인 경우 왼쪽 view만 보여지도록 설정(imgOther, tvOtherMsg~~)
자신의 id인 경우 오른쪽 view만 보여지도록 설정(tvMyMSG, tvMyTime)

ChatVO


public class ChatVO {
    private int imgId;
    private String name;
    private String msg;
    private String time;

    public ChatVO(){}

    public ChatVO(int imgId, String name, String msg, String time) {
        this.imgId = imgId;
        this.name = name;
        this.msg = msg;
        this.time = time;
    }

    public int getImgId() {
        return imgId;
    }

    public void setImgId(int imgId) {
        this.imgId = imgId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMsg() {
        return msg;
    }

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

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

PersonVO


import android.app.Person;

public class PersonVO {
    private String name;
    private int age;
    private boolean gender;

    public PersonVO(){}
    public PersonVO(String name, int age, boolean gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public boolean isGender() {
        return gender;
    }

    public void setGender(boolean gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "PersonVO{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }
}

chat_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content">

    <ImageView
        android:id="@+id/imgOther"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="4dp"
        android:layout_marginTop="16dp"
        app:layout_constraintBottom_toTopOf="@+id/guideline2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        app:srcCompat="@android:drawable/sym_def_app_icon" />

    <TextView
        android:id="@+id/tvOtherNm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="12dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        android:textSize="20sp"
        app:layout_constraintStart_toEndOf="@+id/imgOther"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvOtherMsg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="12dp"
        android:layout_marginTop="8dp"
        android:text="TextView"
        android:textSize="20sp"
        app:layout_constraintBottom_toTopOf="@+id/guideline2"
        app:layout_constraintStart_toEndOf="@+id/imgOther"
        app:layout_constraintTop_toBottomOf="@+id/tvOtherNm"
        app:layout_constraintVertical_bias="0.075" />

    <TextView
        android:id="@+id/tvOtherTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="12dp"
        android:layout_marginBottom="36dp"
        android:text="TextView"
        app:layout_constraintBottom_toTopOf="@+id/guideline2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toEndOf="@+id/tvOtherMsg" />

    <TextView
        android:id="@+id/tvMyTime"
        android:layout_width="59dp"
        android:layout_height="14dp"
        android:layout_marginStart="260dp"
        android:text="TextView"
        app:layout_constraintBottom_toTopOf="@+id/guideline2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvOtherTime"
        app:layout_constraintVertical_bias="0.666" />

    <TextView
        android:id="@+id/tvMyMsg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#FFEB3B"
        android:text="TextView"
        android:textSize="20sp"
        app:layout_constraintBottom_toTopOf="@+id/guideline2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.384"
        app:layout_constraintStart_toEndOf="@+id/tvMyTime"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.941" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="116dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

activity_chat2.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:backgroundTint="#03A9F4"
    tools:context=".ChatActivity">

    <ListView
        android:id="@+id/ChatList"
        android:layout_width="413dp"
        android:layout_height="0dp"
        android:layout_marginBottom="13dp"
        android:background="#FFEB3B"
        app:layout_constraintBottom_toTopOf="@+id/btnSend"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/edtMsg"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPersonName"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btnSend"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/btnSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"
        android:backgroundTint="#FBE200"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="@+id/edtMsg"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/edtMsg"
        app:layout_constraintVertical_bias="0.157" />
</androidx.constraintlayout.widget.ConstraintLayout>
profile
초보 코딩

0개의 댓글