View - RecyclerView



reference:

https://developer.android.com/guide/topics/ui/layout/recyclerview 





 RecyclerView 개요

RecyclerView는 양이 많거나 자주 바뀌는 데이터의 목록을 표시하는 데에 사용합니다. ListView의 개선된 버전이라고 볼 수 있습니다. 

RecyclerView에서 데이터를 표현하기 위해서는 몇가지 요소들이 같이 작동해야 합니다. 

RecyclerView 

기본적으로 ListView와 마찬가지로 뷰를 표시하는 컨테이너로서, layout에 추가되는 요소입니다.

Layout manager

RecyclerView에 제공하여 목록에 아이템을 채우는 역할을 합니다. LinearLayoutManager, GridLayoutManager 등 기존의 layout manager를 사용하거나 직접 만들 수 있습니다.

View holder

목록 안의 아이템들은 view holder 객체로서 표현됩니다. 이 객체들은 RecyclerView.ViewHolder 클래스를 상속 받은 객체입니다. 하나의 아이템을 표현하는 역할을 합니다. RecyclerView는 목록의 아이템 갯수 만큼 view holder 객체를 생성합니다. 사용자가 스크롤 하면 ReyclerView는 화면에서 가려진 아이템을 회수해서 새로 보여질 아이템을 보여주는데 사용합니다.

View holder 객체는 RecyclerView.Adapter 클래스를 상속받은 adpater에 의해 관리됩니다. Adpater 클래스는 필요에 의해 view holder를 만들고, 또한 view holder에 표시할 데이터를 바인드합니다. 이것은 view holder를 아이템의 위치(position)에 할당한 후 adpater의 onBindViewHolder() 메소드를 호출하는 것으로 이루어집니다. 위치에 따라 데이터의 어떤 컨텐츠를 표시할 것인지 결정하는 것입니다.

RecyclerView에서는 다음과 같은 최적화가 되어있습니다:

    • 목록이 처음 결정되면, 그 목록 일부의 대한 view holder를 생성하고 바인드합니다. 예를 들어, 0부터 9 위치의 목록이 표시된다면 RecyclerView는 9까지 view holder를 만들고 바인드합니다. 그리고 10번의 view holder를 만들고 바인드할 수도 있는 것입니다. 이 방법으로, 스크롤 되었을 때 표시할 아이템을 준비시켜놓는 것입니다.

    • 유저가 목록을 스크롤하면, RecyclerView는 필요에 따라 새로운 view holder를 만듭니다. 그리고 화면 바깥으로 밀려난 아이템에 대한 view holder들을 저장하여 다시 사용될 수 있게 합니다. 만약 스크롤 중에 반대방향으로 스크롤하면 저장되어있던 view holder를 바로 불러와서 표시하게 됩니다. 반면에 계속 같은 방향으로 스크롤하면 밀려난 위치의 view holder가 새롭게 표시될 아이템에 다시 바인드 됩니다. View holder는 새로 생성되거나 새로운 view를 inlfate 시킬 필요가 없습니다. 대신 새로운 아이템에 대해서 바인드를 새로하는 것입니다.

    • 표시된 아이템이 변한다면, adapter에 알리면 됩니다(RecyclerView.Adapter.notify...() 메소드). Adpater의 코드가 영향을 미치는 아이템에 대해 다시 바인드시킵니다. 


 RecyclerView 사용하기

Activity에서 다음과 같이 layout에 추가된 RecyclerView를 사용하도록 합니다.

@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
        setContentView
(R.layout.my_activity);
        mRecyclerView
= (RecyclerView) findViewById(R.id.my_recycler_view);

       
// use this setting to improve performance if you know that changes
       
// in content do not change the layout size of the RecyclerView
        mRecyclerView
.setHasFixedSize(true);

       
// use a linear layout manager
        mLayoutManager
= new LinearLayoutManager(this);
        mRecyclerView
.setLayoutManager(mLayoutManager);

       
// specify an adapter (see also next example)
        mAdapter
= new MyAdapter(myDataset);
        mRecyclerView
.setAdapter(mAdapter);
   
}

LinearLayoutManager로 설정해놓아 일렬로 표시되도록 하고, setAdapter()를 통해 adapter를 설정했습니다.

다음은 adapter 클래스입니다.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
   
private String[] mDataset;

   
// 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 mTextView;
       
public MyViewHolder(TextView v) {
           
super(v);
            mTextView
= v;
       
}
   
}

   
// Provide a suitable constructor (depends on the kind of dataset)
   
public MyAdapter(String[] myDataset) {
        mDataset
= myDataset;
   
}

   
// Create new views (invoked by the layout manager)
   
@Override
   
public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
                                                   
int viewType) {
       
// create a new view
       
TextView v = (TextView) LayoutInflater.from(parent.getContext())
               
.inflate(R.layout.my_text_view, 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
        holder
.mTextView.setText(mDataset[position]);

   
}

   
// Return the size of your dataset (invoked by the layout manager)
   
@Override
   
public int getItemCount() {
       
return mDataset.length;
   
}
}

위 adpater은 TextView를 하나 사용하는 아이템에 대한 행동을 정의하고 있습니다. 표시할 아이템들의 목록을 필드로 갖고, 바인드되었을 때 어떻게 아이템을 표시할 것인지 onBindViewHolder()에 정의했습니다. 또한 처음 bind되었을 때 어떻게 view holder를 만들 것인지 onCreateViewHolder()에 정의했습니다. 이 예시에서는 아이템에 대한 layout을 inflate하고 그 view를 가지고 view holder를 만들도록 했습니다. 이 메소드 안에서는 어떻게 아이템을 표시할 것인지 정의하지 않습니다.


추가적으로, 다음과 같은 기본 제공 layout manager를 사용할 수도 있습니다.

LinearLayoutManager : 1차원의 목록을 일렬로 표시, ListView와 같이 표시됨

GridLayoutManager : 2차원의 grid로 표시함.

StaggeredGridLayoutManger : 아이템의 offset이 살짝 서로간에 다른 2차원 grid로 표현함(예를 들어미국 국기의 별들)

 

Conclusion

RecyclerView은 여러 최적화를 거친 ListView입니다. 데이터를 view holder에 바인드 시켜 어떻게 표시할 것인지 정의합니다. 또한 layout manager를 통해 어떤 식으로 목록을 표시할 것인지 customize할 수 있습니다. 

View holder는 아이템이 바인드될 view를 갖는 클래스입니다. 기존에 ListView에서 방식은 findView하는 과정이 반복되었는데, view holder를 통해 이를 개선한 효과도 있습니다.

표시할 데이터가 변했을 때 adpater에 이를 알리면 onBindViewHolder() 메소드가 호출되어 다시 표시하도록 합니다. 


아이템 목록

-> Adpater에 연결

-> Adpater가 position에 따라 해당 위치의 데이터를 표시가능한 형태(View holder)로 연결

-> 목록이 변했음을 adapter에 알리면, 목록을 view holder에 다시 바인드

-> 새롭게 bind된 목록을 다시 RecyclerView에 표시

'programming > android' 카테고리의 다른 글

Thread with Handler & AsyncTask  (0) 2018.08.27
ViewGroup  (0) 2018.08.24
View - AppWidget  (0) 2018.08.23
View - Widget  (0) 2018.08.23
Companion Objects in Kotlin  (0) 2018.04.08

+ Recent posts