programing

RecyclerView 어댑터 데이터 업데이트 방법

yoursource 2023. 9. 4. 22:59
반응형

RecyclerView 어댑터 데이터 업데이트 방법

는 업데이트의 인지 알고 싶습니다.RecyclerView의 어댑터.

새로운 제품 목록을 받은 후 다음을 시도했습니다.

  1. ArrayList의 단편에서.recyclerView되어 새 생되고새데를어댑로설터정다호다음니출합한성이를 호출합니다.adapter.notifyDataSetChanged()그것은 작동하지 않았습니다.

  2. 것처럼 어댑터를 만들고, 에게 효과가 나에게는 변화가 : 다른사람했것새어다생해작저만지니아없변습었무화.recyclerView.setAdapter(new RecyclerViewAdapter(newArrayList))

  3. 에서 메소드 Adapter다음과 같이 데이터를 업데이트합니다.

     public void updateData(ArrayList<ViewModel> viewModels) {
        items.clear();
        items.addAll(viewModels);
        notifyDataSetChanged();
     }
    

    그런 다음 데이터 목록을 업데이트하고 싶을 때마다 이 메소드를 호출합니다. 작동하지 않았습니다.

  4. recyclerView를 수정할 수 있는지 확인하고 항목을 하나 이상 제거하려고 했습니다.

      public void removeItem(int position) {
         items.remove(position);
         notifyItemRemoved(position);
     }
    

모든 것이 그대로 남아 있었습니다.

다음은 내 어댑터입니다.

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements View.OnClickListener {

    private ArrayList<ViewModel> items;
    private OnItemClickListener onItemClickListener;

    public RecyclerViewAdapter(ArrayList<ViewModel> items) {
        this.items = items;
    }


    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false);
        v.setOnClickListener(this);
        return new ViewHolder(v);
    }

    public void updateData(ArrayList<ViewModel> viewModels) {
        items.clear();
        items.addAll(viewModels);
        notifyDataSetChanged();
    }
    public void addItem(int position, ViewModel viewModel) {
        items.add(position, viewModel);
        notifyItemInserted(position);
    }

    public void removeItem(int position) {
        items.remove(position);
        notifyItemRemoved(position);
    }


    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        ViewModel item = items.get(position);
        holder.title.setText(item.getTitle());
        Picasso.with(holder.image.getContext()).load(item.getImage()).into(holder.image);
        holder.price.setText(item.getPrice());
        holder.credit.setText(item.getCredit());
        holder.description.setText(item.getDescription());

        holder.itemView.setTag(item);
    }


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


    @Override
    public void onClick(final View v) {
        // Give some time to the ripple to finish the effect
        if (onItemClickListener != null) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    onItemClickListener.onItemClick(v, (ViewModel) v.getTag());
                }
            }, 0);
        }
    }

    protected static class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView image;
        public TextView price, credit, title, description;

        public ViewHolder(View itemView) {
            super(itemView);
            image = (ImageView) itemView.findViewById(R.id.image);
            price = (TextView) itemView.findViewById(R.id.price);
            credit = (TextView) itemView.findViewById(R.id.credit);
            title = (TextView) itemView.findViewById(R.id.title);
            description = (TextView) itemView.findViewById(R.id.description);
        }
    }

    public interface OnItemClickListener {

        void onItemClick(View view, ViewModel viewModel);

    }
}

그리고 나는 시작합니다.RecyclerView다음과 같이:

recyclerView = (RecyclerView) view.findViewById(R.id.recycler);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 5));
adapter = new RecyclerViewAdapter(items);
adapter.setOnItemClickListener(this);
recyclerView.setAdapter(adapter);

그렇다면 새로 받은 항목을 표시하기 위해 어댑터 데이터를 실제로 업데이트하려면 어떻게 해야 합니까?


문제는 gridView가 있는 레이아웃이 다음과 같이 보인다는 것이었습니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:tag="catalog_fragment"
    android:layout_height="match_parent">

    <FrameLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

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

        <ImageButton
            android:id="@+id/fab"
            android:layout_gravity="top|end"
            style="@style/FabStyle"/>

    </FrameLayout>
</LinearLayout>

그리고 난 그냥 제거했어요.LinearLayout그리고 만든FrameLayout상위 레이아웃으로 표시됩니다.

이것은 일반적인 대답입니다.어댑터 데이터를 업데이트하는 다양한 방법이 설명되어 있습니다.이 프로세스에는 매번 두 가지 주요 단계가 포함됩니다.

  1. 데이터 세트 업데이트
  2. 어댑터에 변경 사항 알림

단일 항목 삽입

"돼지에 "2.

Insert single item
String item = "Pig";
int insertIndex = 2;
data.add(insertIndex, item);
adapter.notifyItemInserted(insertIndex);

여러 항목 삽입

색인에 세 마리의 동물을 더 삽입합니다.2.

Insert multiple items
ArrayList<String> items = new ArrayList<>();
items.add("Pig");
items.add("Chicken");
items.add("Dog");
int insertIndex = 2;
data.addAll(insertIndex, items);
adapter.notifyItemRangeInserted(insertIndex, items.size());

단일 항목 제거

목록에서 "돼지"를 제거합니다.

Remove single item
int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);

여러 항목 제거

목록에서 "카멜"과 "양"을 제거합니다.

Remove multiple items
int startIndex = 2; // inclusive
int endIndex = 4;   // exclusive
int count = endIndex - startIndex; // 2 items will be removed
data.subList(startIndex, endIndex).clear();
adapter.notifyItemRangeRemoved(startIndex, count);

모든 항목 제거

전체 목록을 지웁니다.

Remove all items
data.clear();
adapter.notifyDataSetChanged();

이전 목록을 새 목록으로 바꾸기

이전 목록을 지우고 새 목록을 추가합니다.

Replace old list with new list
// clear old list
data.clear();

// add new list
ArrayList<String> newList = new ArrayList<>();
newList.add("Lion");
newList.add("Wolf");
newList.add("Bear");
data.addAll(newList);

// notify adapter
adapter.notifyDataSetChanged();

adapter 에대언한있다습니급이에 대한 .data그래서 제가 설정하지 않은 것이 중요합니다.data새로운 목적을 위해.대신에, 나는 오래된 물건들을 치웠습니다.data그리고 새로운 것들을 추가했습니다.

단일 항목 업데이트

"양" 항목을 "양이 좋아요"라고 표시되도록 변경합니다.

Update single item
String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);

단일 항목 이동

"을 " 위치에서 합니다.3치에의 위치를 1.

Move single item
int fromPosition = 3;
int toPosition = 1;

// update data array
String item = data.get(fromPosition);
data.remove(fromPosition);
data.add(toPosition, item);

// notify adapter
adapter.notifyItemMoved(fromPosition, toPosition);

코드

여기 당신이 참고할 프로젝트 코드가 있습니다.RecyclerView 어댑터 코드는 이 답변에서 확인할 수 있습니다.

기본 활동.java

public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {

    List<String> data;
    MyRecyclerViewAdapter adapter;

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

        // data to populate the RecyclerView with
        data = new ArrayList<>();
        data.add("Horse");
        data.add("Cow");
        data.add("Camel");
        data.add("Sheep");
        data.add("Goat");

        // set up the RecyclerView
        RecyclerView recyclerView = findViewById(R.id.rvAnimals);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
                layoutManager.getOrientation());
        recyclerView.addItemDecoration(dividerItemDecoration);
        adapter = new MyRecyclerViewAdapter(this, data);
        adapter.setClickListener(this);
        recyclerView.setAdapter(adapter);
    }

    @Override
    public void onItemClick(View view, int position) {
        Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
    }

    public void onButtonClick(View view) {
        insertSingleItem();
    }

    private void insertSingleItem() {
        String item = "Pig";
        int insertIndex = 2;
        data.add(insertIndex, item);
        adapter.notifyItemInserted(insertIndex);
    }

    private void insertMultipleItems() {
        ArrayList<String> items = new ArrayList<>();
        items.add("Pig");
        items.add("Chicken");
        items.add("Dog");
        int insertIndex = 2;
        data.addAll(insertIndex, items);
        adapter.notifyItemRangeInserted(insertIndex, items.size());
    }

    private void removeSingleItem() {
        int removeIndex = 2;
        data.remove(removeIndex);
        adapter.notifyItemRemoved(removeIndex);
    }

    private void removeMultipleItems() {
        int startIndex = 2; // inclusive
        int endIndex = 4;   // exclusive
        int count = endIndex - startIndex; // 2 items will be removed
        data.subList(startIndex, endIndex).clear();
        adapter.notifyItemRangeRemoved(startIndex, count);
    }

    private void removeAllItems() {
        data.clear();
        adapter.notifyDataSetChanged();
    }

    private void replaceOldListWithNewList() {
        // clear old list
        data.clear();

        // add new list
        ArrayList<String> newList = new ArrayList<>();
        newList.add("Lion");
        newList.add("Wolf");
        newList.add("Bear");
        data.addAll(newList);

        // notify adapter
        adapter.notifyDataSetChanged();
    }

    private void updateSingleItem() {
        String newValue = "I like sheep.";
        int updateIndex = 3;
        data.set(updateIndex, newValue);
        adapter.notifyItemChanged(updateIndex);
    }

    private void moveSingleItem() {
        int fromPosition = 3;
        int toPosition = 1;

        // update data array
        String item = data.get(fromPosition);
        data.remove(fromPosition);
        data.add(toPosition, item);

        // notify adapter
        adapter.notifyItemMoved(fromPosition, toPosition);
    }
}

메모들

  • 사용하는 경우notifyDataSetChanged()그러면 애니메이션이 수행되지 않습니다. 드는일 수 에 또이작비많들사수있않좋다것습니용이는한지하로으이므용이업은,다▁this▁recomm좋니습▁use▁is▁not또한▁toended▁can를 사용하지 않는 것이 좋습니다.notifyDataSetChanged()단일 항목 또는 항목 범위만 업데이트하는 경우.
  • 목록을 크게 또는 복잡하게 변경하는 경우 DiffUtil을 확인하십시오.

추가 연구

저는 RecyclerView에서 작업하고 있으며 제거와 업데이트 모두 잘 작동합니다.

  1. 제거:

    RecyclerView에서 항목을 제거하는 4단계가 있습니다.

     list.remove(position);
     recycler.removeViewAt(position);
     mAdapter.notifyItemRemoved(position);
     mAdapter.notifyItemRangeChanged(position, list.size());
    

    이 코드 라인들은 저에게 효과가 있습니다.

  2. 모든 데이터 업데이트:

    제가 해야 할 일은 다음과 같습니다.

     mAdapter.notifyDataSetChanged();
    

    모든 항목에 영향을 미치기 때문에 애니메이션이 없습니다.

RecyclerView의 어댑터 자체가 "데이터 관리자"(그리고 "제거(intos)" 및 "추가(...)"와 같은 방법을 사용하지 않는 한, Activity/Fragment 코드와 같이 "데이터"가 관리되는 곳에서 이 모든 작업을 수행해야 합니다.

이것이 저에게 도움이 되었습니다.

recyclerView.setAdapter(new RecyclerViewAdapter(newList));
recyclerView.invalidate();

업데이트된 목록이 포함된 새 어댑터(내 경우 ArrayList로 변환된 데이터베이스)를 생성하고 어댑터로 설정한 후recyclerView.invalidate()그리고 그것은 성공하였다.

이 작업에는 두 가지 옵션이 있습니다.

어댑터에서 UI를 새로 고칩니다.

mAdapter.notifyDataSetChanged();

또는 recyclerView 자체에서 새로 고치십시오.

recyclerView.invalidate();

또 다른 옵션은 diffil을 사용하는 것입니다.원래 목록을 새 목록과 비교하고 변경 사항이 있는 경우 새 목록을 업데이트로 사용합니다.

기본적으로 DiffUtil을 사용하여 이전 데이터와 새 데이터를 비교하고 알림을 호출할 수 있습니다.ItemRange 제거됨, 알림ItemRange가 변경되어 알림항목 범위 사용자를 대신하여 삽입합니다.

notifyDataSetChanged 대신 diffUtil을 사용하는 간단한 예:

DiffResult diffResult = DiffUtil
                .calculateDiff(new MyDiffUtilCB(getItems(), items));

//any clear up on memory here and then
diffResult.dispatchUpdatesTo(this);

//and then, if necessary
items.clear()
items.addAll(newItems)

비동기 목록을 사용하여 큰 목록인 경우 메인 스레드에서 diff 작업을 계산합니다.

목록 보기, 그리드 보기 및 재활용 보기의 데이터를 업데이트합니다.

mAdapter.notifyDataSetChanged();

또는:

mAdapter.notifyItemRangeChanged(0, itemList.size());

저는 같은 문제를 다른 방법으로 해결했습니다.데이터가 없습니다.백그라운드 스레드에서 기다리고 있으니 빈 목록부터 시작하세요.

mAdapter = new ModelAdapter(getContext(), new ArrayList<Model>());
// Then when I get data

mAdapter.update(response.getModelList());
// And update it in my adapter

public void update(ArrayList<Model> modelList){
    adapterModelList.clear();
    for (Product model: modelList) {
        adapterModelList.add(model);
    }
   mAdapter.notifyDataSetChanged();
}

바로 그겁니다.

현재 데이터에 새 데이터를 추가하는 가장 좋은 방법은 다음과 같습니다.

 ArrayList<String> newItems = new ArrayList<String>();
 newItems = getList();
 int oldListItemscount = alcontainerDetails.size();
 alcontainerDetails.addAll(newItems);           
 recyclerview.getAdapter().notifyItemChanged(oldListItemscount+1, al_containerDetails);

DiffUtil을 탐색하는 것이 좋습니다.또한 목록 업데이트를 처리하는 동안 RecyclerView의 성능이 향상됩니다.

  1. 어댑터 내부의 변수를 정의합니다.

     differList = AsyncListDiffer(this, this.callback);     
     differList.submitList(list)
    

여기서 목록은 초기 원시 목록이거나 나중에 업데이트할 경우 빈 목록일 수 있습니다.

  1. 콜백 구현 중:

    private val callback : DiffUtil.ItemCallback<Item> = object: DiffUtil.ItemCallback<Item>() {
    
       override fun areItemsTheSame(oldItem: Item, newItem: Item) =
         oldItem.id == newItem.id
    
       override fun areContentsTheSame(oldItem: Item, newItem: Item) =
         oldItem == newItem
     }
    
  2. 또한 동일한 어댑터에서 목록을 설정할 수 있는 공용 기능이 있습니다.

     fun setData(list: List<Item>) {
            differList.submitList(list)
            //yeah, that's it!
     }
    
  1. 이제 목록을 변경한 후(삽입/업데이트/삭제) 조각/활동에서 이 setData(목록)를 호출합니다.

    mAdapter.setData(list)

쉽죠?

인 방법을 사용하는 것이 이고 좋습니다.RecyclerView.

private List<YourItem> items;

public void setItems(List<YourItem> newItems)
{
    clearItems();
    addItems(newItems);
}

public void addItem(YourItem item, int position)
{
    if (position > items.size()) return;

    items.add(item);
    notifyItemInserted(position);
}

public void addMoreItems(List<YourItem> newItems)
{
    int position = items.size() + 1;
    newItems.addAll(newItems);
    notifyItemChanged(position, newItems);
}

public void addItems(List<YourItem> newItems)
{
    items.addAll(newItems);
    notifyDataSetChanged();
}

public void clearItems()
{
    items.clear();
    notifyDataSetChanged();
}

public void addLoader()
{
    items.add(null);
    notifyItemInserted(items.size() - 1);
}

public void removeLoader()
{
    items.remove(items.size() - 1);
    notifyItemRemoved(items.size());
}

public void removeItem(int position)
{
    if (position >= items.size()) return;

    items.remove(position);
    notifyItemRemoved(position);
}

public void swapItems(int positionA, int positionB)
{
    if (positionA > items.size()) return;
    if (positionB > items.size()) return;

    YourItem firstItem = items.get(positionA);

    videoList.set(positionA, items.get(positionB));
    videoList.set(positionB, firstItem);

    notifyDataSetChanged();
}

어댑터 클래스 내에서 또는 조각 또는 활동에서 이를 구현할 수 있지만, 이 경우 어댑터를 인스턴스화하여 알림 메서드를 호출해야 합니다.저의 경우에는 주로 어댑터에 구현합니다.

RecyclerView를 다시 로드하는 정말 간단한 방법은 전화를 하는 것입니다.

recyclerView.removeAllViews();

이렇게 하면 먼저 RecyclerView의 모든 내용이 제거된 다음 업데이트된 값으로 다시 추가됩니다.

▁use▁i▁▁you▁to▁strongly합장을 사용하는 것을 강력히 추천합니다.[DiffUtil.ItemCallback][1]변를화처위해의 변경 하기 위해RecyclerView.Adapter:

fun setData(data: List<T>) {
    val calculateDiff = DiffUtil.calculateDiff(DiffUtilCallback(items, data))
    items.clear()
    items += data
    calculateDiff.dispatchUpdatesTo(this)
}

후드 아래에서는 대부분의 작업을 처리합니다.AdapterListUpdateCallback:

/**
 * ListUpdateCallback that dispatches update events to the given adapter.
 *
 * @see DiffUtil.DiffResult#dispatchUpdatesTo(RecyclerView.Adapter)
 */
public final class AdapterListUpdateCallback implements ListUpdateCallback {
    @NonNull
    private final RecyclerView.Adapter mAdapter;

    /**
     * Creates an AdapterListUpdateCallback that will dispatch update events to the given adapter.
     *
     * @param adapter The Adapter to send updates to.
     */
    public AdapterListUpdateCallback(@NonNull RecyclerView.Adapter adapter) {
        mAdapter = adapter;
    }

    /** {@inheritDoc} */
    @Override
    public void onInserted(int position, int count) {
        mAdapter.notifyItemRangeInserted(position, count);
    }

    /** {@inheritDoc} */
    @Override
    public void onRemoved(int position, int count) {
        mAdapter.notifyItemRangeRemoved(position, count);
    }

    /** {@inheritDoc} */
    @Override
    public void onMoved(int fromPosition, int toPosition) {
        mAdapter.notifyItemMoved(fromPosition, toPosition);
    }

    /** {@inheritDoc} */
    @Override
    public void onChanged(int position, int count, Object payload) {
        mAdapter.notifyItemRangeChanged(position, count, payload);
    }
}

코틀린과 함께라면, 어댑터를 사용할 것입니다.

class ProductAdapter(var apples: List<Apples>?= null) : RecyclerView.Adapter<ProductViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {...}

    override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {...}

    override fun getItemCount(): Int {...}

    fun setData(newApples: List<Apples>) {
        apples = newApples
    }
}

조각/활동 중

val appleAdapter = ProductAdapter()

val recyclerView = binding.appleRecycler // or findViewById or synthetics or whatever. 
recyclerView.adapter = appleAdapter
recyclerView.layoutManager = LinearLayoutManager(requireContext())

이제 fragment의 데이터 변경 사항을 처리하는 중입니다.

fun updateRecyclerData(apples: List<Apples>){
    adapter.setData(apples)
    adapter.notifyDataSetChanged()
}

updateRecyclerData(applesList)

저는 오랜만에 답을 얻었습니다.

SELECTEDROW.add(dt);
notifyItemInserted(position);
SELECTEDROW.remove(position);
notifyItemRemoved(position);

이것은 잘 작동합니다. 해보세요.

  ArrayList.remove(position);
  notifyItemRemoved(position);
  notifyDataSetChanged();

위의 설명에 언급된 내용이 없으면 문제가 다른 곳에 있다는 것을 의미할 수 있습니다.

해결책을 찾은 한 곳은 어댑터에 목록을 설정하는 방법이었습니다.제 활동에서 목록은 인스턴스 변수였고 데이터가 변경될 때 직접 변경했습니다.참조 변수이기 때문에 이상한 일이 있었습니다.

에 서저그참변로변변컬다경수른고변다사수니전에데습했다달음래업이한데를이트터용여로 했습니다.addAll()앞의 답변에 언급된 함수입니다.

언급URL : https://stackoverflow.com/questions/31367599/how-to-update-recyclerview-adapter-data

반응형