是否有任何Observers在RecyclerView.Adapter中编写,以了解数据集是否已更改?

Nik*_*hil 14 android observers notifydatasetchanged recycler-adapter android-recyclerview

RecyclerView用它实现了Custom Adapter如下

全球宣言如下

private LinearLayoutManager linearLayoutManager;
private int pastVisibleItems, visibleItemCount, totalItemCount;
private CustomRecyclerViewAdapter customRecyclerViewAdapter;
Run Code Online (Sandbox Code Playgroud)

首先,我在onCreate()方法内部创建了适配器实例,其中包含Empty Array并将其设置为recyclerView

linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
    Utility.ItemDecorationConst);
recyclerView.addItemDecoration(dividerItemDecoration);
customRecyclerViewAdapter = new CustomRecyclerViewAdapter(getActivity());

recyclerView.setAdapter(customRecyclerViewAdapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

    visibleItemCount = linearLayoutManager.getChildCount();
    totalItemCount = linearLayoutManager.getItemCount();
    pastVisibleItems = linearLayoutManager.findFirstVisibleItemPosition();
    if (loading) {
        if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
            loading = false;
            customRecyclerViewAdapter.addProgressBarEntry();
            controller.getNextPage(PublisherAppContainerFragment.this);
        }
    }
}
});
Run Code Online (Sandbox Code Playgroud)

渲染完成时查看我从中获取数据以AsyncTask进行填写recyclerView

我调用以下方法Adapter来填充数据

customRecyclerViewAdapter.addAll(myArray);
Run Code Online (Sandbox Code Playgroud)

注意:addAll()不是任何重写方法

以下是我的代码 CustomRecyclerViewAdapter

class CustomRecyclerViewAdapter extends RecyclerView.Adapter<CustomRecyclerViewAdapter.ViewHolder> {
    ArrayList<MyModel> arrayList = new ArrayList<>();
    Context context;

    public CustomRecyclerViewAdapter(Context context) {
        this.context = context;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewHolder viewHolder = null;
        //inflated some view
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        //binded data to holder
    }

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

    public void addAll(ArrayList myArray) {
        this.arrayList.addAll(myArray)
    }

    public void clear() {
        arrayList.clear();
    }
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public CardView cardView;

        public ViewHolder(View view) {
        super(view);
            this.cardView = (CardView) view.findViewById(R.id.card_view);
            this.cardView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
        //handle operations
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以每当我从AsynTask我调用方法获取数据addAll()并且recyclerView像魅力一样工作.

现在,我的问题是它如何工作得很好,尽管我从来没有叫notifyDataSetChanged()上了adapter.是否有任何先前注册的适配器观察员?如果已返回的数据集public int getItemCount()已更改,谁会观察到?

正如我读到的那样 documentation

void notifyDataSetChanged()

通知任何已注册的观察员数据集已更改.

这意味着即使有一些observers注册,你需要notify使用它们notifyDataSetChanged().对?

我也打过电话

boolean flag = customRecyclerViewAdapter.hasObservers();
Run Code Online (Sandbox Code Playgroud)

要知道是否有任何观察员注册?FlagTrue.

所以任何人都愿意帮助我理解这些东西究竟是如何运作的?

Gau*_*tam 5

如果你查看 RecyclerView setAdapter 调用的源代码,你会发现一个方法setAdapterInternal(adapter, false, true);负责

将当前适配器替换为新适配器并触发侦听器。

此方法负责将旧适配器与新适配器交换,并且在内部它还注册自定义Data Observer。这就是您将标志设为true的原因


hap*_*ude 2

根据我对您的代码的了解,我想说您的代码中没有任何观察者RecyclerView正在获取更改并保持列表更新。更有可能的是,您只是“幸运”,因为当您滚动列表时,布局管理器不断调用getItemCount()适配器以确定是否应该显示更多项目。每当您调用 时addAll(),您都会默默地更新项目计数,而观察者恰好会收到有关更改的通知。

这绝对是一个错误,如果您依赖于特定观察者来监视列表的某些方面,或者做的不仅仅是将新项目附加到底部(例如更改或插入),您更有可能在实现中看到它的影响现有项目之间)。正如您所指出的,正确的实现是在列表更新时调用notifyDataSetChanged(),或者如果可以的话,最好更具体地说明更改的内容。例如,您可以使用:

public void addAll(ArrayList myArray) {
    int positionStart = getItemCount() - 1;
    this.arrayList.addAll(myArray);
    notifyItemRangeInserted(positionStart, myArray.size());
}

public void clear() {
    int oldSize = getItemCount();
    arrayList.clear();
    notifyItemRangeRemoved(0, oldSize);
}
Run Code Online (Sandbox Code Playgroud)