본문 바로가기

안드로이드

안드로이드 리사이클러뷰(RecyclerView) 실습

안드로이드 리사이클러뷰에 대한 개념을 설명한 이후 2달이 지난거 같다... 너무 바빠서 이제야 코드를 올리고 코드에 대한 설명을 올리려 한다. 

실습에 앞서 개발 워크플로우와 이번 실습에서 보일 결과를 먼저 설명 후에 코드에 대한 설명을 하도록하겠다.

 


 


아래는 실습을 진행할 워크플로우와 최종 결과물이다. 3개의 클래스와 2개의 레이아웃으로 우측의 결과물을 만들 수 있다. 아마 설명을 하면서 지난번 올려놨던 '안드로이드 리사이클러뷰(RecyclerView) 개념' 설명이 자주 언급될거 같으니 참고하고 실습을 해보면 좋을거 같다. 코드의 설명은 워크플로우 순서에 맞춰 설명하도록 하겠다.

 

실습에 앞서 RecyclerView를 사용하기 위해서는 app.gradle에 implementation 'com.android.support:recyclerview-v7:28.0.0' 을 추가해줘야 한다. 뒤에 버전 v7:28.0.0은 자신의 appcompat와 동일한 버전으로 맞춰주면 된다. 그럼 레이아웃에서 RecyclerView 사용이 가능해진다.

 

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

 

정말 간단하다. 그냥 아래를 복붙 하면 기존 리스트뷰를 만들던것 처럼 Item0 ~ Item9 가 보일거다.

 


<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>

 

2. 리사이클러뷰 아이템 뷰 레이아웃 추가 (item.xml)

 

이 부분은 개인이 커스터마이징 하는 부분이다. 나의 경우는 이름과 전화번호를 출력하게 레이아웃을 설정하였다. 당연하게도 리스트 출력의 커스터마이징을 통해 넓이와 어떠한 데이터를 표시할지는 개인이 맞춰서 레이아웃을 만들어주면 된다.

 


    <TextView
        android:id="@+id/name_user"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="20dp"
        android:layout_marginStart="20dp"
        android:paddingLeft="20dp"
        android:text="이름 입력" />

    <TextView
        android:id="@+id/number_user"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="right"
        android:paddingRight="10dp"
        android:paddingTop="75dp"
        android:text="000-1234-5678"
        android:textColor="@android:color/darker_gray"
        android:textSize="9dp" />

 

3. 리사이클러뷰 어댑터 구현 (RecyclerViewAdapter.java)

 

이제 본격적으로 리사이클러뷰를 위한 구현이다. 리사이클러뷰에 표시될 아이템 뷰를 생성하는 역할을 담당하며, 사용자 데이터 리스트로부터 아이템뷰를 만드는 역할을 담당한다.

 

(리스트뷰의 경우 안드로이드 SDK에서 제공되는 어댑터를 사용했던거와 달리 리사이클러뷰는 사용자가 직접 어댑터를 직접 구현해줘야함)

 

리사이클러뷰는 리스트뷰와 달리 직접 어댑터를 생성해줘야하며, RecyclerView.Adapter를 상속받아 새로운 어댑터를 만들때 필수적으로 오버라이드를 해줘야 하는 메소드는 3가지가 존재한다.

 


Method 설명
onCreateViewHolder(ViewGroup parent, int viewType) viewType에 해당하는 ViewHolder를 생성하여 return
onBindViewHolder(ViewHolder holder, int position) 어댑터가 해당 position에 해당하는 데이터를 결합
getItemCount() 전체 아이템 갯수 return

 

어댑터의 동작원리는 다음과 같다!!! 중요하다!!!

어댑터의 내부 동작의 경우 getItemCount가 호출되어 총 item의 갯수가 몇개인지 판단하고, onCreateViewHolder에서 viewType에 해당하는 ViewHolder를 생성하여 return 한다. (ViewHolder 객체 생성)

 

(여기서 기존 리스트뷰와 차별화된 리사이클러뷰의 강점이 보인다. 리사이클러뷰는 앞서 말했듯이 ViewHolder 사용을 강제화 하였다. 실제로 아이템 목록을 보여줄때 메시지, 이미지 와 같이 다양한 타입을 보여주는 경우가 발생한다. 이럴때 ListView의 getView()로 구현은 가능하지만, 코드가 굉장히 복잡해진다. 이럴때 onCreateViewHolder에서 타입에 맞는 ViewHolder를 객체를 생성하여 return해주며, ViewHolder를 통해 가독성이 좋아진다. 결국 각 item 다양한 view의 정보를 가지고 있는 친구는 ViewHolder이다.)

 

이후 onBindViewHolder()이 호출되어 ViewHolder의 객체와 리스트에서 해당 ViewHolder의 위치를 인자로 전달한다. 어댑터는 인자로 받은 위치에 맞는 데이터를 찾은 후 그것을 ViewHolder의 View에 결합하게 된다.

 


public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    private Activity activity;
    private List<Person> person;
    private MainActivity ac;

    public RecyclerViewAdapter(Activity activity, List<Person> person) {
        this.activity = activity;
        //MainActivity의 recyclerViewAdapter = new RecyclerViewAdapter(this,person); person 연관
        this.person = person;
    }

    //data 갯수 반환
    @Override
    public int getItemCount() {
        return person.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        TextView name;
        TextView number;

        public ViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.name_user);
            number = (TextView) itemView.findViewById(R.id.number_user);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(activity, "click " +
                            person.get(getAdapterPosition()).getName(), Toast.LENGTH_SHORT).show();
                }
            });

            itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    Toast.makeText(activity, "remove " +
                            person.get(getAdapterPosition()).getName(), Toast.LENGTH_SHORT).show();
                    removeItemView(getAdapterPosition());
                    return false;
                }
            });
        }
    }

    //뷰 홀더를 생성하고 뷰를 붙여주는 부분
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    // 재활용 되는 View가 호출, Adapter가 해당 position에 해당하는 데이터를 결합
    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        Person data = person.get(position);

        // 데이터 결합
        holder.name.setText(data.getName());
        holder.number.setText(data.getNumber());
    }

    private void removeItemView(int position) {
        person.remove(position);
        notifyItemRemoved(position);
        notifyItemRangeChanged(position, person.size()); // 지워진 만큼 다시 채워넣기.
    }
}

 

4. Getter/Setter 생성 (Person.java)

 


public class Person {

    private String name;
    private String number;

    public Person(String name, String number) {
        this.name = name;
        this.number = number;
    }

    public String getName() {
        return name;
    }

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

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }
}

 

5. 리사이클러뷰에 어댑터와 레이아웃 매니저 지정 (MainActivity.java)

 

마지막으로 위에서 작성한 RecyclerViewAdapter.java 어댑터에 대한 객체와 레이아웃매니저의 객체를 생성한 후 

각 객체를 setLayoutManager() 메서드를 통해 리사이클러뷰에 저장하는 것이다.


public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    LinearLayoutManager linearLayoutManager;
    //RecyclerViewAdapter class
    RecyclerViewAdapter recyclerViewAdapter;

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

        //activity_main.xml의 recyclerview id
        recyclerView = findViewById(R.id.recyclerView);
        linearLayoutManager = new LinearLayoutManager(this);

        //recyclerview 항목들 사이에 구분선 추가
        //수평, 수직의 스크롤 리스트 / getOrientation을 이용하여 스크롤 방향 설정
        recyclerView.addItemDecoration(
                new DividerItemDecoration(this,linearLayoutManager.getOrientation()));

        //지정된 레이아웃매니저를 RecyclerView에 Set
        recyclerView.setLayoutManager(linearLayoutManager);

        // ArrayList에 person 객체(이름과 번호) 넣기
        List<Person> person = new ArrayList<>();
        person.add(new Person("Test","010-1234-5678"));
        person.add(new Person("NEO","010-5678-1234"));
        person.add(new Person("STACK","010-3412-7856"));
        person.add(new Person("TestPerson","123-1256-3478"));

        // Adapter생성
        recyclerViewAdapter = new RecyclerViewAdapter(this,person);
        recyclerView.setAdapter(recyclerViewAdapter);

    }
}

 

마지막으로 참고할 자료를 찾던 중 리사이클러뷰의 동작원리를 정말 잘 설명한 블로그가 있어서 일부분만 캡처하여 올려놓겠다. 

 

출처: https://programmingfbf7290.tistory.com/entry/이해하기-쉬운-RecyclerView

 

 

이번에 실습한 코드는 깃허브에 올려놓았다. 만약 제대로 작동이 하지 않는다면 댓글 남겨주세용~~

 

너무졸리다 굿밤

 

 

https://github.com/songtaegeon/android_recyclerview