Android

RecyclerView 와 Adapter 를 이용하여 리스트를 화면에 표시하는 방법

yugyeong 2023. 1. 31. 17:56

 

 

1. RecyclerView 란?

RecyclerView  리싸이클러뷰는 리스트 모양으로 보여줄 수 있는 선택위젯 중 가장 권장하는 위젯이다.

여러 개의 아이템 중에 하나를 선택할 수 있는 리스트 모양의 위젯을 선택 위젯이라고 부른다.
선택 위젯을 구분하는 이유는 선택 위젯이 어댑터 패턴을 사용하기 때문이다. 

 

 

2. Adapter클래스 만들기

리스트 모양의 뷰에 보이는 각각의 아이템은 뷰가 아닌 어댑터에서 관리한다. 
getView() : 이 메서드에서 반환하는 뷰가 하나의 아이템으로 디스플레이된다. 
대부분의 어댑터에서 반환하는 객체가 리니어 레이아웃과 같은 컨테이너 객체이다. 

 

Adapter 클래스는 RecyclerView.Adapter 클래스를 상속하도록한다.

public class PersonAdapter extends RecyclerView.Adapter{ 


해당 클래스를 상속하게 되면 3가지 구현해야하는 메서드가 생긴다. 

 

onCreateViewHolder() : 

뷰홀더가 새로 만들어질 때 호출, 각 아이템을 위해 정의한 xml 레이아웃을 이용해 뷰 객체를 만든다. 메서드 안에서 인플레이션을 진행. 파라미터로 전달되는 뷰그룹 객체는 각 아이템을 위한 뷰그룹 객체이므로 xml 레이아웃을 인플레이션하여 이 뷰그룹 객체에 설정한다. 

 

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
	LayoutInflater inflater = LayoutInflater.from(parent.getContext());
	View itemView = inflater.inflate(R.layout.movie_item, parent, false);
	
    // View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_item, parent, false);
    
	return new ViewHolder(itemView);
}


onBindViewHolder() : 

뷰홀더가 재사용될 때 호출되므로 뷰객체는 기존 것을 그대로 사용하고 데이터만 바꾼다. 뷰홀더 객체를 파라미터로 전달 받기 때문에, 뷰홀더에 현재 아이템에 맞는 데어팀나 설정하면 된다. 전달된 position 파라미터를 이용해 ArrayList에서 객체를 꺼내어 설정할 수 있다.  

 

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
 
 //Glide 이용하여 이미지 보여주기
  Glide.with(holder.itemView).load(items.get(position).getProfileUri()).into(holder.imageView);
  holder.textView.setText(items.get(position).getName());
  holder.textView2.setText(items.get(position).getTel());
}

 

getItemCount() :

어댑터에서 관리하는 아이템의 개수 반환, 어댑터가 ArrayList 안에 들어있는 객체의 수를 알아야 하므로 ArrayList의 size() 메서드롤 호출하여 아이템의 개수를 얻는다. 

 

@Override
public int getItemCount() {
	return items.size();
}


각각의 아이템은 뷰로 만들어지며, 각각의 아이템을 위한 뷰는 뷰홀더에 담아두게 됩니다.
뷰홀더 : 각각의 아이템을 위한 뷰를 담고 있는 것
이 뷰홀더 역할을 하는 클래스를 Adapter 클래스 안에 넣어둔다.


RecyclerView.ViewHolder 클래스를 상속하여 정의된 ViewHolder 클래스의 생성자에는 뷰 객체가 전달된다. 전달 받은 객체를 부모 클래스의 변수에 담아둔다.

static class ViewHolder extends RecyclerView.ViewHolder {

  public ViewHolder(View itemView){
    super(itemView);
  }
}



3. MainActivity 클래스 수정하기

 

LinearLayoutManager 객체를 만든다.
리싸이클러뷰에 레이아웃 매니저를 설정하기위해 setLayoutManager() 메서드롤 호출한다.
Adapter 객체를 만들고 setAdapter() 메서드를 호출한다.

RecyclerView recyclerView = findViewById(R.id.recyclerView); 
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); 
recyclerView.setLayoutManager(layoutManager); 
PersonAdapter adapter = new PearsonAdapter(); 
recyclerView.setAdapter(adapter); 



4. Item ClickListener 만들기 (ClickListener 인터페이스 만들기)

public interface OnPersonClickListener { 
    public void onItemClick(PersonAdapter.ViewHolder holder, View view, int position); 
} 



5. 뷰홀더 클래스의 itemView에 OnClickListener만들기

public ViewHolder(View itemView,final OnProductClickListener listener){ 
  super(itemView); 
  imageView = itemView.findViewById(R.id.imageView); 
  textView2 = itemView.findViewById(R.id.textView2); 
  textView3 = itemView.findViewById(R.id.textView3); 

  itemView.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View view) { 
      int position = getAdapterPosition(); 
      if(listener!=null){ 
      	listener.onItemClick(ViewHolder.this, view, position); 
      } 
    } 
  }); 
} 



6. onCreateViewHolder return 값 바꾸기

return new ViewHolder(itemView, this);


7. 어댑터 클래스에 인터페이스 구현하기

public class PersonAdapter extends RecyclerView.Adapter implements OnPersonClickListener{ 

  OnPersonItemClickListener listener; 

	//중략

	// 외부에서 리스너를 설정할 수 있도록 메서드 추가. 
  public void setOnItemClickListener(OnPersonClickListener listener){ 
  	this.listener = listener; 
  } 

  @Override 
  public void onItemClick(ViewHolder holder, View view, int position) { 
    if(listener != null){ 
    	listener.onItemClick(holder, view, position); 
    } 
  } 
}

 

 

 

 

MainActivity

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private RecyclerView.Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;
    private ArrayList<User> arrayList;
    private FirebaseDatabase database;
    private DatabaseReference databaseReference;


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

        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        arrayList = new ArrayList<User>();

        database = FirebaseDatabase.getInstance(); // 파이어베이스 데이터베이스 연동
        databaseReference = database.getReference("User");
        databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                // firebase 데이터베이스의 데이터를 받아오는 곳
                arrayList.clear(); // 기존 배열리스트 존재하지 않게 초기화
                for (DataSnapshot snapshot : dataSnapshot.getChildren()) { // 반복문으로 데이터 List 추출
                    User user = snapshot.getValue(User.class); // 만들어뒀던 User 객체에 데이터를 담는다.
                    arrayList.add(user); // 담은 데이터를 배열리스트에 넣고 리사이클러뷰로 보낼준비
                }
                adapter.notifyDataSetChanged();  // 리스트 저장 및 새로고침
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) { // 데이터베이스 가져오던 중 에러 발생시
                Log.e("MainActivity", String.valueOf(databaseError.toException()));
            }
        });

        adapter = new UserAdapter(arrayList, this);
        recyclerView.setAdapter(adapter);
    }
}

 

UserAdapter

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

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;

import java.util.ArrayList;

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserViewHolder> {

    private ArrayList<User> arrayList;
    private Context context;

    public UserAdapter(ArrayList<User> arrayList, Context context) {
        this.arrayList = arrayList;
        this.context = context;
    }

    @NonNull
    @Override
    public UserViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);

        return  new UserViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
        Glide.with(holder.itemView)
                .load(arrayList.get(position).getProfile()).into(holder.iv_profile);
        holder.tv_id.setText(arrayList.get(position).getId());
        holder.tv_pw.setText(String.valueOf(arrayList.get(position).getPw()));
        holder.tv_name.setText(arrayList.get(position).getName());
    }

    @Override
    public int getItemCount() {
        return arrayList != null ? arrayList.size() : 0 ;
    }

    public class UserViewHolder extends RecyclerView.ViewHolder {
        ImageView iv_profile;
        TextView tv_id, tv_pw, tv_name;

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

            iv_profile = itemView.findViewById(R.id.iv_prof);
            tv_id = itemView.findViewById(R.id.tv_id);
            tv_pw = itemView.findViewById(R.id.tv_pw);
            tv_name = itemView.findViewById(R.id.tv_name);
        }

    }
}