如何在 RecyclerView 适配器中更新特定项目范围

huangapple go评论110阅读模式
英文:

How to update specific item range in recyclerview adapter

问题

我有一个recyclerView。我从服务器获取一个列表,并在我的列表中显示出来。我有分页功能,当我滚动到底部时,我会请求服务器获取接下来的50个项目。唯一的问题是,当我收到响应时,我正在使用notifyDataSetChanged()来更新整个适配器。

mViewModel.getList().observe(
    getViewLifecycleOwner(),
    listResult -> {
        recycler.getAdapter().notifyDataSetChanged();
    });

很简单,我正在使用ViewModel。当我的观察者发出通知时,我调用notifyDataSetChanged()。我的适配器从ViewModel获取列表。当我从服务器获取下一个50个项目时,我只是将新项目添加到现有列表中。在调用notifyDataSetChanged()之后,适配器会使用这50个新项目更新整个列表。那么,我如何只更新从服务器获取的最后50个项目呢?当我将这些项目添加到列表中时,我需要通知适配器更新其数据。在那里,我找到了notifyItemInserted();,但它需要位置。

英文:

I have a recyclerView. I'm fetching a list from server and show it in my list. I have pagination and when I scroll to bottom, I request the server to get next e.g. 50 items. The only problem is, when I get the response, I'm updating the whole adapter, using notifyDataSetChanged().

mViewModel.getList().observe(
			getViewLifecycleOwner(),
			listResult -> {
				recycler.getAdapter().notifyDataSetChanged();
			});

That's simple, I'm using ViewModel. When my observer notifies, I call notifyDataSetChanged(). My adapter gets the list from ViewModel. And when I'm getting next 50 items from server, I just add the new items to an existing list. And after calling notifyDataSetChanged() adapter updates the whole list with this new 50 items. So how can I update only the last 50 items, that I get from server? When I add this items into list, I need to notify adapter to update its data. There I found one notifyItemInserted();, but it needs position.

答案1

得分: 1

你可以使用DiffUtilsAsyncListDiffer来完成这项工作(我告诉你这个,但我并没有完全理解它的内部工作原理)。它可以使绘制变得简单,并由Android系统处理。我在一些帖子中读到并了解到,AsyncListDiffer会检查新项目,并且只绘制那些新项目。

以下是一些代码来帮助你:

适配器类

import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.AsyncListDiffer;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.SortedSet;

import neilsayok.github.launchertest5.R;
import neilsayok.github.launchertest5.adapter.viewholder.AppDrawerItemVH;
import neilsayok.github.launchertest5.data.AppInfo;

public class AppDrawerRVAdapter extends RecyclerView.Adapter<AppDrawerItemVH> {

    private Context context;
    private AsyncListDiffer<AppInfo> appList;

    public AppDrawerRVAdapter(Context context) {
        this.context = context;
        appList = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<AppInfo>() {

            @Override
            public boolean areItemsTheSame(@NonNull AppInfo oldItem, @NonNull AppInfo newItem) {
                return TextUtils.equals(oldItem.getPackageName(), newItem.getPackageName());
            }

            @Override
            public boolean areContentsTheSame(@NonNull AppInfo oldItem, @NonNull AppInfo newItem) {
                return TextUtils.equals(newItem.getLable(), oldItem.getLable());
            }
        });
    }

    public void submitList(SortedSet<AppInfo> data) {
        appList.submitList(new ArrayList<>(data));
    }

    @NonNull
    @Override
    public AppDrawerItemVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new AppDrawerItemVH(LayoutInflater.from(context).inflate(R.layout.app_drawer_item, parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull AppDrawerItemVH holder, int position) {
        final AppInfo app = appList.getCurrentList().get(position);
        holder.getAppIcon().setImageDrawable(app.getAppIcon());
        holder.getAppLable().setText(app.getLable());

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(app.getPackageName());
                context.startActivity(launchIntent);
            }
        });
    }

    @Override
    public int getItemCount() {
        if (appList == null)
            return 0;
        else
            return appList.getCurrentList().size();
    }
}

AppInfo类 (这是我用来参考的POJO类)

import android.graphics.drawable.Drawable;

public class AppInfo {
    private String lable;
    private String packageName;
    private Drawable appIcon;

    public AppInfo() {
    }

    public AppInfo(String lable, String packageName, Drawable appIcon) {
        this.lable = lable;
        this.packageName = packageName;
        this.appIcon = appIcon;
    }

    public String getLable() {
        return lable;
    }

    public void setLable(String lable) {
        this.lable = lable;
    }

    public String getPackageName() {
        return packageName;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    public Drawable getAppIcon() {
        return appIcon;
    }

    public void setAppIcon(Drawable appIcon) {
        this.appIcon = appIcon;
    }
}

在您的ViewModel观察者中更改此行代码:
recycler.getAdapter().notifyDataSetChanged(); 更改为 appDrawerRVAdapter.submitList(appInfos); 其中_appDrawerRVAdapter_ 是适配器对象。

使用这种方法,您将不再需要调用 notifydatachanged() 或类似的方法。这个链接对我帮助很大。

英文:

You can use DiffUtils With AsyncListDiffer to do the work(I am telling you this but I do not properly understand how it works internally). It makes the drawing easy and handled by the Android System. I have read and found on some posts that AsyncListDiffer checks for new Items and only draw the items that are new.

Here is some codes to help you:

Adapter Class

import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.AsyncListDiffer;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.SortedSet;

import neilsayok.github.launchertest5.R;
import neilsayok.github.launchertest5.adapter.viewholder.AppDrawerItemVH;
import neilsayok.github.launchertest5.data.AppInfo;

public class AppDrawerRVAdapter extends RecyclerView.Adapter&lt;AppDrawerItemVH&gt; {


    private Context context;

    private AsyncListDiffer&lt;AppInfo&gt; appList;


    public AppDrawerRVAdapter(Context context) {
        this.context = context;
        appList = new AsyncListDiffer&lt;&gt;(this, new DiffUtil.ItemCallback&lt;AppInfo&gt;() {

            @Override
            public boolean areItemsTheSame(@NonNull AppInfo oldItem, @NonNull AppInfo newItem) {
                return TextUtils.equals(oldItem.getPackageName(), newItem.getPackageName());
            }

            @Override
            public boolean areContentsTheSame(@NonNull AppInfo oldItem, @NonNull AppInfo newItem) {
                return TextUtils.equals(newItem.getLable(), oldItem.getLable());
            }
        });
    }

    public void submitList(SortedSet&lt;AppInfo&gt; data) {
        appList.submitList(new ArrayList&lt;AppInfo&gt;(data));
    }


    @NonNull
    @Override
    public AppDrawerItemVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new AppDrawerItemVH(LayoutInflater.from(context).inflate(R.layout.app_drawer_item,
                parent, false));
    }

    @Override
    public void onBindViewHolder(@NonNull AppDrawerItemVH holder, int position) {
        final AppInfo app = appList.getCurrentList().get(position);
        holder.getAppIcon().setImageDrawable(app.getAppIcon());
        holder.getAppLable().setText(app.getLable());

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(app.getPackageName());
                context.startActivity(launchIntent);
            }
        });
    }

    @Override
    public int getItemCount() {
        if (appList == null)
            return 0;
        else
            return appList.getCurrentList().size();    }
}

AppInfo Class (This is my POJO class just given for reference)

import android.graphics.drawable.Drawable;

public class AppInfo {
    private String lable;
    private String packageName;
    private Drawable appIcon;

    public AppInfo() {
    }

    public AppInfo(String lable, String packageName, Drawable appIcon) {
        this.lable = lable;
        this.packageName = packageName;
        this.appIcon = appIcon;
    }

    public String getLable() {
        return lable;
    }

    public void setLable(String lable) {
        this.lable = lable;
    }

    public String getPackageName() {
        return packageName;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    public Drawable getAppIcon() {
        return appIcon;
    }

    public void setAppIcon(Drawable appIcon) {
        this.appIcon = appIcon;
    }
}


Change this line in your ViewModel Observer:

recycler.getAdapter().notifyDataSetChanged(); to appDrawerRVAdapter.submitList(appInfos); where appDrawerRVAdapter is the adapter object.

With this method you will not have to call notifydatachanged() or something like that too.This Link helped me a lot.

huangapple
  • 本文由 发表于 2020年5月5日 00:27:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/61596987.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定