안드로이드 노트

[프로젝트1] 가입한 회원들의 리스트를 만들기 - Android RecyclerView, CardView, firebase

devRobin 2022. 3. 20. 22:15
RecyclerView 기본 사용법 워크플로우

1) 메인 액티비티에 리사이클러뷰 추가.

2) 아이템 뷰 레이아웃 추가

3) 리사이클러뷰 어댑터 구현.(extends RecyclerView_Adpater)

4) 어댑터, 레이아웃매니저 지정(setAdapter(), setLayoutManager())

 

참고:

https://recipes4dev.tistory.com/154

 

 

1.build.gradle(모듈)에 다음과 같은 문장을 추가하고 싱크 now를 해준다.

  implementation 'androidx.recyclerview:recyclerview:1.2.1'
  implementation 'androidx.cardview:cardview:1.0.0'

 

 

2.row_user.xml에 다음과 같이 CardView와 함께 리스트 한 칸에 들어갈 레이아웃을 구성해준다. (아이템 뷰 레이아웃 추가)

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:cardUseCompatPadding="true"
    app:cardElevation="2dp"
    app:cardCornerRadius="2dp"
    app:cardBackgroundColor="@color/white"
    app:contentPadding="3dp">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/avatarIv"
            android:background="@drawable/ic_default_img"
            android:layout_width="70dp"
            android:layout_height="70dp"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <TextView
                android:id="@+id/nameTv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Person Name"
                android:textSize="18sp"
                android:textColor="@color/black"/>
            <TextView
                android:id="@+id/emailTv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Person Email"
                android:textColor="@color/black"/>


        </LinearLayout>

    </LinearLayout>
</androidx.cardview.widget.CardView>

사진과 같이 구성해준다.

 

CardView란?

CardView란 RecyclerView 내의 레이아웃에 사용되는 컨테이너.

카드를 사용하면 간편하게 컨테이너의 스타일을 일관되게 유지하면서 뷰 그룹을 포함할 수 있다.

 

참고:

https://blog.addsoft.co.kr/34

 

 

3. fragment_users. xml에 다음과 같이 recyclerview를 만들어준다.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".UsersFragment">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/users_recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

</FrameLayout>

 

4. UsersFragment에서 다음과 같은 작업을 해준다.

1) Inflate the layout for this fragment

2) init recyclerview

3) set it's properties

public class UsersFragment extends Fragment {

    RecyclerView recyclerView;
 

    public UsersFragment(){
        //Required empty public constructor
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        
        //Inflate the layout for this fragment
        View view= inflater.inflate(R.layout.fragment_users,container,false);

        //init recyclerview
        recyclerView= view.findViewById(R.id.users_recyclerView);
        
        //set it's properties
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

      

        return view;
    }
Inflate란?

안드로이드에서 Inflate의 정의는 xml에 표기된 레이아웃들을 메모리에 객체화시키는 행동이다.

 

onCreateView()란?

Layout을 inflate하는 곳, View 객체를 얻어서 초기화.

 

recyclerVeiw.setHasFixedSize(true);의 의미는?

아이템 항목을 추가할 때마다 RecyclerView의 크기는 변경된다. 크기가 변경되기 때문에 레이아웃을 그릴 때, 크기를 측정하고 다시 그리는 것을 반복할 것이다. setHasFixedSize의 기능은 RecyclerView의 크기 변경이 일정하다는 것을 사용자의 입력으로 확인한다. 항목의 높이나 너비가 변경되지 않으며, 추가 또는 제거된 모든 항목은 동일하다. 

 

출처:

https://woovictory.github.io/2020/06/24/Android-RecyclerView-Attr/

 

 

 

5. ModelUser 클래스를 만들어준다. (Model Class for recyclerview)

주의: Use same name as in firebase database.

1) Generate -> Constructor

2) Generate -> Getter and Setter

public class ModelUser {

    //use same name as in firebase database
    String name, email, desc, image, uid;

    public ModelUser(){

    }

    public ModelUser(String name, String email, String desc, String image, String uid) {
        this.name = name;
        this.email = email;
        this.desc = desc;
        this.image = image;
        this.uid = uid;
    }

    public String getName() {
        return name;
    }

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

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }
}
자바 클래스 생성자(Constructor), getter/setter란?

생성자(Constructor): 객체가 생성될 때 자동으로 실행되는 특수한 메소드.

특징: 리턴형을 명시하지 않는다. 클래스와 이름이 동일하다. 오버로딩 또한 가능.

 

Getter/Setter는 클래스의 특성 중 정보 은닉을 가장 잘 보여주는 메소드.

 

참고: https://maktooob.tistory.com/35

 

 

6. AdapterUsers를 만든다. (리사이클러뷰 어댑터 구현)

리사이클러뷰에서는 반드시 개발자가 어댑터를 직접 구현해야 한다. 그리고 이 때 새로 만드는 어댑터는 RecyclerView.Adapter를 상속하여 구현해야 한다.

 

RecyclerView.Adapter를 상속받아 새로운 어댑터를 만들 때, 오버라이드가 필요한 메서드는 아래와 같다.

 

1) onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
2) onBindViewHolder(@NonNull MyHolder holder, int position)
3) getItemCount()

1) viewType 형태의 아이템 뷰를 위한 뷰홀더 객체 생성.

2) position에 해당하는 데이터를 뷰홀더의 아이템뷰에 표시

3) 전체 아이템 갯수 리턴.

 

참고: https://recipes4dev.tistory.com/154

 

public class AdapterUsers extends RecyclerView.Adapter<AdapterUsers.MyHolder>{

    Context context;
    List<ModelUser> userList;

    //constructor
    public AdapterUsers(Context context, List<ModelUser> userList){
        this.context = context;
        this.userList = userList;
    }
    
    //아이템 뷰를 저장하는 뷰홀더 클래스
    class MyHolder extends RecyclerView.ViewHolder{

        ImageView mAvatarIv;
        TextView mNameTv, mEmailTv;

        public MyHolder(@NonNull View itemView) {
            super(itemView);

            //뷰 객체에 대한 참조.
            mAvatarIv = itemView.findViewById(R.id.avatarIv);
            mNameTv= itemView.findViewById(R.id.nameTv);
            mEmailTv= itemView.findViewById(R.id.emailTv);
        }
    }
    

	//아이템뷰를 위한 뷰홀더 객체 생성하여 리턴.
    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //inflate layout(row_user.xml)
        View view = LayoutInflater.from(context).inflate(R.layout.row_users, parent, false);
        return new MyHolder(view);
    }

	//position에 해당하는 데이터를 뷰홀더의 아이템뷰에 표시
    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
        //get data
        String userImage = userList.get(position).getImage();
        String userName = userList.get(position).getName();
        String userEmail = userList.get(position).getEmail();

        //set data
        holder.mNameTv.setText(userName);
        holder.mEmailTv.setText(userEmail);
        try{
            Picasso.get().load(userImage).placeholder(R.drawable.ic_default_img).into(holder.mAvatarIv);
        } catch (Exception e){

        }

        //handle item click
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context,""+userEmail,Toast.LENGTH_SHORT).show();
            }
        });

    }

	//전체 데이터 갯수 리턴
    @Override
    public int getItemCount() {
        return userList.size();
    }

 
}

 

 

7. UsersFragment에서 4번에 이어 다음과 같이 작업해준다.

public class UsersFragment extends Fragment {

    RecyclerView recyclerView;
    AdapterUsers adapterUsers;
    List<ModelUser> userList;

    public UsersFragment(){
        //Required empty public constructor
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //Inflate the layout for this fragment
        View view= inflater.inflate(R.layout.fragment_users,container,false);

        //init recyclerview
        recyclerView= view.findViewById(R.id.users_recyclerView);
        //set it's properties
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        //init user list
        userList = new ArrayList<>();

        //getAll users
        getAllUsers();

        return view;
    }

 

8. getAllUsers()

    private void getAllUsers() {
        //get current user
        FirebaseUser fUser = FirebaseAuth.getInstance().getCurrentUser();
        //get path of database named "Users" containing users info
        DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Users");
        //get all data from path
        ref.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                userList.clear();
                for (DataSnapshot ds: snapshot.getChildren()){
                    ModelUser modelUser = ds.getValue(ModelUser.class);

                    //get all users except currently signed in user
                    if(!modelUser.getUid().equals(fUser.getUid())){
                        userList.add(modelUser);

                    }

                    //adapter
                    adapterUsers = new AdapterUsers(getActivity(), userList);
                    //set adapter to recycler view
                    recyclerView.setAdapter(adapterUsers);

                }
            }

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

            }
        });
    }

 

참고: https://recipes4dev.tistory.com/154

3.5리사이클러뷰에 어댑터와 레이아웃매니저 지정하기

 

기타 참고 자료:

https://www.youtube.com/watch?v=nRGZchw5z7s