레이블이 RecyclerView인 게시물을 표시합니다. 모든 게시물 표시
레이블이 RecyclerView인 게시물을 표시합니다. 모든 게시물 표시

2019년 6월 7일 금요일

안드로이드 RecyclerView 예제

- RecyclerView.ViewHolder 적용
- androidx.recyclerview.widget.DiffUtil 적용


1. RecyclerView.Adapter 구현
public class TextRecyclerAdapter extends RecyclerView.Adapter<TextRecyclerAdapter.Holder> {
    private LayoutInflater inflater;
    private final ArrayList<String> items = new ArrayList<>();

    public void updateList(final List<String> newItems) {
        TextDiff callback = new TextDiff(this.items, newItems);
        DiffUtil.DiffResult result = DiffUtil.calculateDiff(callback);
        this.items.clear();
        this.items.addAll(newItems);
        result.dispatchUpdatesTo(this);
    }

    @NonNull
    @Override
    public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (inflater == null)
            inflater = LayoutInflater.from(parent.getContext());

        View itemView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
        return new Holder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull Holder holder, int position) {
        holder.bindData(getItem(position));

    }

    public String getItem(int position) {
        return items != null && position < getItemCount() ? items.get(position) : null;
    }

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

    static class Holder extends RecyclerView.ViewHolder {
        private final TextView text;

        public Holder(@NonNull View itemView) {
            super(itemView);
            this.text = itemView.findViewById(android.R.id.text1);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Object tag = v.getTag();
                    if (tag instanceof String) {

                    }
                }
            });
        }

        public void bindData(String item) {
            itemView.setTag(item);
            if (item == null)
                return;
            text.setText(item);
        }
    }

    static class TextDiff extends DiffUtil.Callback {
        private final List<String> oldItems;
        private final List<String> newItems;

        public TextDiff(List<String> oldItems, List<String> newItems) {
            this.oldItems = oldItems;
            this.newItems = newItems;
        }

        @Override
        public int getOldListSize() {
            return oldItems.size();
        }

        @Override
        public int getNewListSize() {
            return newItems.size();
        }

        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            if (oldItemPosition > newItemPosition)
                return false;
            return oldItems.get(oldItemPosition).equals(newItems.get(oldItemPosition));
        }

        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            if (oldItemPosition > newItemPosition)
                return false;
            return oldItems.get(oldItemPosition).equals(newItems.get(oldItemPosition));
        }
    }
}


- ViewHolder 클래스를 구현해서 사용한다.
- DiffUtil 클래스를 구현해서 리스트 갱신을 효율적으로 구현한다.






2. RecyclerView 구현
public class RecyclerListFragment extends Fragment {

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

    public static RecyclerListFragment newInstance() {
        RecyclerListFragment fragment = new RecyclerListFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_recycler_list, container, false);
        RecyclerView recyclerView = view.findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext());
        linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
        TextRecyclerAdapter textRecyclerAdapter = new TextRecyclerAdapter();
        recyclerView.setAdapter(textRecyclerAdapter);

        ArrayList<String> items = new ArrayList<>();
        items.add("Text Item 1");
        items.add("Text Item 2");
        items.add("Text Item 3");
        textRecyclerAdapter.updateList(items);

        return view;
    }
}


- updateList를 호출하면 DiffUtil 기능으로 리스트가 자연스럽게 갱신된다.

2019년 2월 27일 수요일

안드로이드 RecyclerView 예제


- androidx 기준
- 클릭 이벤트, Diffutil 구현 샘플


1. app module dependencies 설정
2019.02.27 기준
implementation 'androidx.recyclerview:recyclerview-selection:1.0.0'

레퍼런스 : https://developer.android.com/jetpack/androidx/migrate





2. DiffUtil.Callback 작성

- DiffUtilCallback
public class DiffUtilCallback extends DiffUtil.Callback {
    private final List<TextItem> oldList;
    private final List<TextItem> newList;

    public DiffUtilCallback(List<TextItem> oldList, List<TextItem> newList) {
        this.oldList = oldList;
        this.newList = newList;
    }

    @Override
    public int getOldListSize() {
        return oldList == null ? 0 : oldList.size();
    }

    @Override
    public int getNewListSize() {
        return newList == null ? 0 : newList.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldList.get(oldItemPosition).getId() == newList.get(newItemPosition).getId();
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldList.get(oldItemPosition).getText().equals(newList.get(newItemPosition).getText());
    }
}






3. RecyclerView.Adapter 구현

- TextItemAdapter
public abstract class TextItemAdapter extends RecyclerView.Adapter<Holder> implements View.OnClickListener {
    private final List<TextItem> list = new ArrayList<>();

    @Override
    public void onClick(View v) {
        ViewParent parent = v.getParent();

        if (parent instanceof RecyclerView) {
            RecyclerView rv = (RecyclerView) parent;

            // 클릭된 포지션 찾기
            int position = rv.getChildAdapterPosition(v);

            TextItem item = list.get(position);
            onItemClick(rv, v, position, item);
        }
    }

    /**
     * 클릭 이벤트
     *
     * @param rv
     * @param view
     * @param position
     * @param item
     */
    public abstract void onItemClick(RecyclerView rv, View view, int position, TextItem item);

    @NonNull
    @Override
    public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
        // 클릭 이벤트
        view.setOnClickListener(this);
        return new Holder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull Holder holder, int position) {
        holder.bindItem(list.get(position));
    }

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

    public void updateList(List<TextItem> newList) {

        // 리스트 갱신
        DiffUtilCallback diffUtilCallback = new DiffUtilCallback(list, newList);
        DiffUtil.DiffResult result = DiffUtil.calculateDiff(diffUtilCallback);

        this.list.clear();
        this.list.addAll(newList);

        result.dispatchUpdatesTo(this);
    }
}



4. 샘플코드
소스코드
APK