ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [RecyclerView.Adapter] RecyclerView 편하게 쓰기
    개발/Android 2018. 4. 8. 23:46
    반응형

     리스트 형태의 UI 개발시 많이 사용하는 RecyclerView를 사용하려면 RecyclerView.Adapter 클래스를 상속받은 Adapter 클래스와 리스트의 항목을 표현할 때 사용되는 RecyclerView.ViewHolder를 상속받은 ViewHolder 클래스를 구현해야 합니다.


     하나의 리스트 화면만 사용하게 되는 경우는 많지 않고 각 리스트 화면은 각각의 특색있는 리스트 항목을 가지는 경우가 많기 때문에 화면별로 Adapter와 ViewHolder를 2개씩 계속 구현해야 하는 경우가 발생합니다.


     리스트 항목에 표시되는 View만 구현하여 사용하는 라이브러리를 만들어 보겠습니다.


     RecyclerView를 사용하는 일반적인 방법은 RecyclerView.Adapter.onBindViewHolder 메소드 동작시 파라매터로 전달받은 RecyclerView.ViewHolder 객체와 position 정보를 이용하여 ViewHolder에 정보를 설정하는 방식으로 동작합니다. 그렇기 때문에 ViewHolder를 Adapter에 맞추어 새로 만들어 주어야 하는 상황이 발생합니다. 이것을 공통 Adapter와 ViewHolder를 생성하여 재사용할 수 있도록 합니다.


     공통 Adapter는 GeneralAdapter, 공통 ViewHolder는 GeneralViewHolder 그리고 ViewHolder에서 생성해야 하는 View 는 GeneralView로 생성합니다.


    
    public class GeneralAdapter extends RecyclerView.Adapter> {
        private Context mContext;
        private Class<?> classType;
    
        ...
        
        @Override
        public void onBindViewHolder(GeneralViewHolder holder, int position) {
            holder.onBindData(position, getItem(position));
        }
    
        @Override
        public GeneralViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            GeneralView cellView;
            try {
                Constructor<?> con = classType.getDeclaredConstructor(Context.class);
                cellView = con.newInstance(parent.getContext());
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            return new GeneralViewHolder<>(cellView);
        }
    
        ...
           
    }
    
    

     onBindViewHolder() 메소드 호출시 ViewHolder 직접 데이터를 설정하지 않고 onBindData() 메소드를 이용하여 전달하게 됩니다.


     onCreateViewHolder() 메소드에서 미리 전달받은 GeneralView를 상속받은 Class정보를 이용하여  GeneralViewHolder를 생성합니다.

    
    public class GeneralViewHolder extends RecyclerView.ViewHolder {
        GeneralView itemView;
        public GeneralViewHolder(GeneralView itemView) {
            super(itemView);
            this.itemView = itemView;
        }
    
        public void onBindData(int position, T data) {
            itemView.onBindData(position, data);
        }
    }
    
    

     기본적으로 별다른 동작은 하지 않고 전달받은 GeneralView 객체를 멤버변수로 등록하여 GeneralAdapter.onBindViewHolder() 메소드 동작시 전달받은 position, data를 전달합니다.


    
    public abstract class GeneralView extends FrameLayout {
        public GeneralView(Context context) {
            super(context);
            View childView = createView(this);
            //recyclerview에 등록시 generalview 가 wrap / wrap으로 적용되기 때문에 원하는 childview의 layoutparam으로 맞춰준다
            setLayoutParams(childView.getLayoutParams());
            addView(childView);
            ButterKnife.bind(this);
        }
    
        public abstract void onBindData(int position, T data);
    
        public abstract View createView(ViewGroup parent);
    }
    
    

     GeneralView는 사용자가 주로 상속받아 구현할 클래스입니다. onBindData(), createView() 메소드가 abstract로 선언이 되어있어서 클래스 구현시 반드시 내용을 구현해야 합니다.

     여기서는 편리하게 사용하기 위해 ButterKnife를 활용했습니다.


     기본이 되는 클래스를 생성하였습니다. 이제 위의 클래스를 활용하여 간단하게 String 리스트를 출력하는 코드를 작성해봅시다.

    
    class ItemView extends GeneralView {
        @BindView(R.id.title)
        TextView title;
        public ItemView (Context context) {
            super(context);
        }
    
        @Override
        public View createView(ViewGroup parent) {
            return LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
        }
    
        @Override
        public void onBindData(int position, String data) {
            title.setText(data);
        }
    }
    
    

     GeneralView를 상속받은 ItemView라는 클래스를 생성합니다. generic은 String으로 맞춰줍니다.

     createView() 에서 리스트 항목에서 표시될 View를 생성하여 반환합니다.  여기서는 ButterKnife를 이용하였기 때문에 별도의 findViewById()를 이용하여 UI를 연결하는 작업을 하지 않습니다.

     마지막으로 onBindData()에서 전달받은 데이터를 TextView에 설정합니다.

    
    RecyclerView recyclerView = findViewById(R.id.recyclerview);
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    recyclerView.setAdapter(new GeneralAdapter(getActivity(), ItemView.class, getStringList()));
    
    

     마지막으로 RecyclerView에 Adapter를 설정합니다.


    RecyclerView를 사용함에 있어서 약간의 편의성을 추가한 정도의 수준이지만 매번 Adapter와 ViewHolder를 생성하지 않아도 되고 RecyclerView를 잘 모르는 사람도 GeneralView만 만들면 사용할 수 있도록 절차가 간소화 되었습니다.


     추가적으로 Click Event는 개발 정책에 따라 GeneralView내부에서 처리하거나 외부로 ClickListener를 연결하거나 하면됩니다.

    반응형
Designed by Tistory.