안드로이드 Do not treat position as fixed; only user immediately and call holder.getAdapterPosition) to look it up later

프로그래밍/Android 관련2018. 2. 27. 17:53

안녕하세요. 개발자 드리머즈입니다.


리싸이클러뷰의 어댑터 구현 중에 워닝 안내이 발생했습니다.


문제 현상


RecyclerView.Adapter의 onBindViewHolder의 2번째 position 인자에서 위 사진과 같은 warning 메세지가 발생했습니다.

워닝 메세지는 아래와 같습니다.


Do not treat position as fixed; only user immediately and call holder.getAdapterPosition() to look it up later

RecyclerView will not call onBindViewHolder again when the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined. For this reason, you should only use the position parameter while acquiring the related data item inside this method, and should not keep a copy of it. If you need the position of an item later on(e.g. in a click listener), use getAdapterPosition() which will have the updated adapter position.

position을 고정된 것으로 여기지 말라고 합니다. click listener등과 같은 방식으로 추후에 position 값을 참조해서는 안되며 추후에 position 값이 필요하면 holder.getAdapterPosition()함수를 사용하라고 합니다.


아래의 getAdapterPosition()함수도 보면 도움이 될 것 같습니다.

RecyclerView does not handle any adapter updates until the next layout traversal. This may create temporary inconsistencies between what user sees on the screen and what adapter contents have. This inconsistency is not important since it will be less than 16ms but it might be a problem if you want to use ViewHolder position to access the adapter. Sometimes, you may need to get the exact adapter position to do some actions in response to user events. In that case, you should use this method which will calculate the Adapter position of the ViewHolder.

정확히 이해는 안가는데 어쨋든 position 대신에 holder.getAdapterPosition()를 사용하라고 합니다.


원인

제가 구현한 onBindViewHolder()함수를 보면 View.OnClickerListener()를 설정하여 onClick()함수를 구현했었습니다.


1
2
3
4
5
6
7
8
9
10
11
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
               ...생략...
                categoryContentViewHolder.rlSubCategory.setOnClickListener(new View.OnClickListener(){
                    @Override
                    public void onClick(View view) {
                        selectedIndex = position;
                    }
                });
                ...생략...
        }
cs

클릭을 통해 onClick() 함수가 불리면 position의 값을 selectedIndex에 저장하는 코드입니다. 이 부분 때문에 warning이 발생하고 있습니다.
onBindViewHolder()가 불리는 시점과 onClick()가 불리는 시점이 다르기에 문제가 된다고 합니다.


해결방법

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        final Item item = data.get(position);
        final CategoryContentViewHolder categoryContentViewHolder = (CategoryContentViewHolder) holder;
        switch (item.type) {
                categoryContentViewHolder.rlSubCategory.setOnClickListener(new View.OnClickListener(){
                    @Override
                    public void onClick(View view) {
                        selectedIndex = categoryContentViewHolder.getAdapterPosition();
                    }
                });
        }
    }
cs

holder를 final 객체에 담고(4번째 라인 코드) onClick()함수에서 position 대신에 categoryContentViewHolder.getAdapterPosition()함수를 사용하면 됩니다(9번째 라인 코드).

작성자

Posted by 드리머즈

관련 글

댓글 영역