RecyclerView
を_Custom Adapter
_で次のように実装しました
次のようなグローバル宣言
_private LinearLayoutManager linearLayoutManager;
private int pastVisibleItems, visibleItemCount, totalItemCount;
private CustomRecyclerViewAdapter customRecyclerViewAdapter;
_
最初に、空のArray
を含むonCreate()
メソッド内にアダプタインスタンスを作成し、それを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);
}
}
}
});
_
完全なビューをレンダリングした後、AsyncTask
からデータを取得してrecyclerView
に入力します
Adapter
の次のメソッドを呼び出して、データを入力します
_customRecyclerViewAdapter.addAll(myArray);
_
注: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
}
}
}
_
したがって、AsynTask
からデータを取得するたびにメソッドaddAll()
を呼び出し、recyclerView
は魅力のように機能します。
さて、私の質問は、adapter
でnotifyDataSetChanged()
を呼び出したことがないのに、どのようにうまく機能しているかということです。アダプター用に以前に登録されたオブザーバーはありますか? public int getItemCount()
で返されたデータセットが変更されたかどうかを誰が観察しますか?
documentation
から読んだように
void notifyDataSetChanged()
登録されたオブザーバーに、データセットが変更されたことを通知します。
つまり、observers
が登録されていても、notifyDataSetChanged()
を使用してnotify
する必要があります。正しい?
私も電話しました
_boolean flag = customRecyclerViewAdapter.hasObservers();
_
登録されているオブザーバーがいるかどうかを知るには? Flag
はTrue
です。
だから誰かが私がこれらのものがどのように正確に機能するかを理解するのを手伝ってくれませんか?
RecyclerView setAdapter呼び出しのソースを見ると、メソッドsetAdapterInternal(adapter, false, true);
があります。
現在のアダプターを新しいアダプターと交換し、リスナーをトリガーします。
このメソッドは、古いアダプターを新しいアダプターと交換する役割を果たし、内部的にはカスタムData Observerにも登録します。これが、フラグをtrueとして取得する理由です。
私の質問は、アダプターでnotifyDataSetChanged()を呼び出したことがないのに、どのようにうまく機能しているかです。
これは、addAllメソッドがデフォルトでnotifyDataSetChanged()
を呼び出すためです。
public void addAll(T ... items) {
synchronized (mLock) {
if (mOriginalValues != null) {
Collections.addAll(mOriginalValues, items);
} else {
Collections.addAll(mObjects, items);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
そして
public void addAll(@NonNull Collection<? extends T> collection) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.addAll(collection);
} else {
mObjects.addAll(collection);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
リンクは次のとおりです- https://github.com/Android/platform_frameworks_base/blob/master/core/Java/Android/widget/ArrayAdapter.Java
編集-ArrayListのaddAllメソッドを呼び出している独自のaddAllメソッドがあることがわかりました。これがaddAllメソッドの仕組みです-
private ArrayList<String> ex1 = new ArrayList();
private ArrayList<String> ex2 = new ArrayList();
private ArrayList<String> ex3 = new ArrayList();
ex1.add("one");
ex2.add("two");
ex3.addAll(ex1);
ex3.addAll(ex2);
System.out.println(ex3);
[〜#〜]出力[〜#〜]-[1、2]
これがあなたの場合に起こっていることです。
_I have shown progress bar and once I fetch data I hide the progress bar and make recyclerView visible
_-レイアウトまたはコードでRecyclerView
可視性GONE
を設定した場合、レイアウトは発生しないため、Adapter.getItemsCount()
は呼び出されません。したがって、データをフェッチしてアダプタ配列にデータを入力し、RecyclerView
の可視性をGONE
からVISIBLE
に変更すると、更新がトリガーされます。
notifyDataSetChanged()
RecyclerView
を呼び出さない場合、更新についてはわかりません。コードには、RecyclerView
更新をトリガーする何かが他にあると思います。この動作を明確にするために、ダミーアダプタを使用してみましょう。
_private class DummyViewHolder extends RecyclerView.ViewHolder {
public DummyViewHolder (View itemView) {
super(itemView);
}
}
private class Adapter extends RecyclerView.Adapter<DummyViewHolder> {
private int mDummySize = 5;
@Override
public DummyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.dummy_view, parent, false);
return new DummyViewHolder(view);
}
@Override
public void onBindViewHolder(DummyViewHolder holder, int position) {
}
void setSize(int size) { this.mDummySize = size; }
@Override
public int getItemCount() {
return mDummySize;
}
}
_
そしてonCraete()
で:
_ ViewHolder v = ...
final Adapter adapter = ..
...
//postpone adapter update
(new Handler()).postDelayed(new Runnable() {
@Override
public void run() {
adapter.setSize(10);//and nothing happend only 5 items on screen
}
}, 5000);
_
私があなたのコードを見ることができることに基づいて、私はあなたの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);
}