notify* 方法不会更新 RecyclerView 的视图
notify* methods doesn't update RecyclerView's view
好吧,我有一个管理联系人的应用程序,我使用 2 RecyclerView
来显示未selected 和 selected 的联系人。用户可以 select 和取消 select 联系人。
这是我的场景:
我有两个 RecyclerView
,一个用于管理 selected 联系人,另一个用于管理未 selected 联系人。当用户 select 未 selected 列表中的联系人时,该联系人将从该列表中删除并插入 selected 列表。如果用户 select 来自 selected 列表的联系人,也会发生同样的情况,只是该联系人从 selected 列表中删除并插入未selected 列表.我实现了自定义 RadioButton
,在 onCheckedChanged
事件中,当 selected 或 unselected.
[= 时,我从适当的适配器中删除了联系人74=]
我有一个适配器用于 selected 列表 (SelectedContactsAdapter
) 和另一个用于未 selected 列表 (UnselectedContactsAdapter
)。我使用新的 SortedList
集合来管理适配器的数据,并在 SortedList
的回调中通知适配器更改并发送回调消息以更新另一个适配器。
例如,如果用户 select 未 selected 列表中的联系人,在 onCheckedChanged
事件中,我会先保存联系人,然后再将其从适配器中删除(我这样做这是因为我需要将它传递给回调,以便它可以插入另一个适配器),然后我从适配器中删除该联系人。这会触发 SortedList
的 onRemoved
方法,然后我调用 notifyItemRemoved(position)
(position
是已删除联系人的位置)和回调以将该联系人插入 select编辑列表。
出于某种原因,notify* 方法不会更新 RecyclerView
视图。我尝试使用 notifyDataSetChanged
并且它有效,但它不是我的选择,因为我需要快速更新,几乎是即时的。
我用 setNestedScrollingEnabled(false)
启动了 2 个 RecyclerView
用于 FastScroll。以防万一...
这是我的代码:
public abstract class FilterableContactsAdapter extends RecyclerView.Adapter<FilterableContactsAdapter.ContactViewHolder>
implements Filterable {
//... Some variables like the filter
protected Contact mLastContactTouched;
protected SortedList<Contact> mFilteredContacts;
protected ContactCallback mContactCallback;
protected boolean mPropagate;
public FilterableContactsAdapter() {
mPropagate = true;
mFilteredContacts = new SortedList<>(Contact.class, new SortedList.Callback<Contact>() {
@Override
public int compare(Contact o1, Contact o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
@Override
public void onChanged(int position, int count) {
notifyItemChanged(position);
if(mContactCallback != null && mPropagate) mContactCallback.onContactChanged(mLastContactTouched, position);
}
@Override
public boolean areContentsTheSame(Contact oldItem, Contact newItem) {
boolean sameIds = (oldItem.getId() == newItem.getId());
boolean sameNames = oldItem.getName().equals(newItem.getName());
boolean samePhoneNumbers = oldItem.getNormalizedPhoneNumber().equals(newItem.getNormalizedPhoneNumber());
if(sameIds && sameNames && samePhoneNumbers) return true;
else return false;
}
@Override
public boolean areItemsTheSame(Contact item1, Contact item2) {
return item1.getId() == item2.getId();
}
@Override
public void onInserted(int position, int count) {
notifyItemInserted(position);
/*if(FilterableContactsAdapter.this instanceof SelectedContactsAdapter) notifyDataSetChanged();
else notifyItemInserted(position);*/
if(mContactCallback != null && mPropagate) mContactCallback.onContactInserted(mLastContactTouched, position);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRemoved(position);
/*if(FilterableContactsAdapter.this instanceof SelectedContactsAdapter) notifyDataSetChanged();
else notifyItemRemoved(position);*/
if(mContactCallback != null && mPropagate) mContactCallback.onContactRemoved(mLastContactTouched, position);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
if(mContactCallback != null && mPropagate) mContactCallback.onContactMoved(mLastContactTouched, fromPosition, toPosition);
}
});
}
public void add(Contact contact) {
mFilteredContacts.add(contact);
}
public void remove(Contact contact) {
mFilteredContacts.remove(contact);
}
//... Some other methods like onCreateViewHolder, the ContactViewHolder declaration and the filter implementation
}
public interface ContactCallback {
void onContactInserted(Contact contact, int adapterPosition);
void onContactRemoved(Contact contact, int adapterPosition);
void onContactMoved(Contact contact, int from, int to);
void onContactChanged(Contact contact, int adapterPosition);
}
public class SelectedContactsAdapter extends FilterableContactsAdapter {
@Override
public void onBindViewHolder(final ContactViewHolder holder, final int position) {
final Contact contact = mFilteredContacts.get(position);
if(contact != null) {
holder.parentLayout.setVisibility(View.VISIBLE);
holder.nameTV.setText(contact.getName());
holder.phoneNumberTV.setText(contact.getNormalizedPhoneNumber());
holder.selectCB.setSafeCheck(true, SafeCheckBox.IGNORE);
holder.selectCB.setOnSafeCheckedListener(new SafeCheckBox.OnSafeCheckedListener() {
@Override
public void onAlwaysCalledListener(CompoundButton buttonView, boolean isChecked) {
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
contact.setSelected(isChecked);
mLastContactTouched = contact;
remove(contact);
}
});
} else {
holder.parentLayout.setVisibility(View.GONE);
}
}
}
public class UnselectedContactsAdapter extends FilterableContactsAdapter {
@Override
public void onBindViewHolder(final ContactViewHolder holder, final int position) {
final Contact contact = mFilteredContacts.get(position);
if(!contact.isSelected()) {
holder.parentLayout.setVisibility(View.VISIBLE);
holder.nameTV.setText(contact.getName());
holder.phoneNumberTV.setText(contact.getNormalizedPhoneNumber());
holder.selectCB.setSafeCheck(false, SafeCheckBox.IGNORE);
holder.selectCB.setOnSafeCheckedListener(new SafeCheckBox.OnSafeCheckedListener() {
@Override
public void onAlwaysCalledListener(CompoundButton buttonView, boolean isChecked) {
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
contact.setSelected(isChecked);
mLastContactTouched = contact;
remove(contact);
}
});
} else {
holder.parentLayout.setVisibility(View.GONE);
}
}
}
public class ContactsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// init the views and setup the searchbar
setupMultiContactsPicker();
}
//... Some other stuff like an OnClick implementation and
//other utility methods that only manage visibility of some
//components of the UI like 2 TextViews and a ProgressBar
private void setupMultiContactsPicker() {
final Filter.FilterListener filterListener = new Filter.FilterListener() {
@Override
public void onFilterComplete(int count) {
progressBar.setVisibility(View.GONE);
updateLayout();
}
};
unselectedContactsAdapter = new UnselectedContactsAdapter();
unselectedContactsAdapter.setContactCallback(new ContactCallback() {
@Override
public void onContactInserted(Contact contact, int adapterPosition) {
selectedContactsAdapter.setPropagate(false);
if(selectedContactsAdapter.getItemCount() > 0) selectedContactsAdapter.remove(contact);
selectedContactsAdapter.setPropagate(true);
updateLayout();
}
@Override
public void onContactRemoved(Contact contact, int adapterPosition) {
selectedContactsAdapter.setPropagate(false);
selectedContactsAdapter.add(contact);
selectedContactsAdapter.setPropagate(true);
updateLayout();
}
@Override
public void onContactMoved(Contact contact, int from, int to) {
}
@Override
public void onContactChanged(Contact contact, int adapterPosition) {
}
});
unselectedContacsRV.setVisibility(View.VISIBLE);
LinearLayoutManager uLayoutManager = new LinearLayoutManager(ContactsActivity.this, LinearLayoutManager.VERTICAL, false);
unselectedContacsRV.setLayoutManager(uLayoutManager);
unselectedContacsRV.setAdapter(unselectedContactsAdapter);
unselectedContacsRV.setHasFixedSize(true);
// Initisialize the adapter with the correct contacts (ContactsFilter.UNSELECTED)
unselectedContactsAdapter.getFilter().filter(FilterableContactsAdapter.ContactsFilter.UNSELECTED, new Filter.FilterListener() {
@Override
public void onFilterComplete(int count) {
onLoadFinish(); //This method call updateLayout(); when the 2 filters finish to load data into the adapters.
}
});
selectedContactsAdapter = new SelectedContactsAdapter();
selectedContactsAdapter.setContactCallback(new ContactCallback() {
@Override
public void onContactInserted(Contact contact, int adapterPosition) {
unselectedContactsAdapter.setPropagate(false);
if(unselectedContactsAdapter.getItemCount() > 0) unselectedContactsAdapter.remove(contact);
unselectedContactsAdapter.setPropagate(true);
updateLayout(); // This method show or hide some TextViews that I use as section titles, nothing more
}
@Override
public void onContactRemoved(Contact contact, int adapterPosition) {
unselectedContactsAdapter.setPropagate(false);
unselectedContactsAdapter.add(contact);
unselectedContactsAdapter.setPropagate(true);
updateLayout(); // This method show or hide some TextViews that I use as section titles, nothing more
}
@Override
public void onContactMoved(Contact contact, int from, int to) {
}
@Override
public void onContactChanged(Contact contact, int adapterPosition) {
}
});
LinearLayoutManager sLayoutManager = new LinearLayoutManager(ContactsActivity.this, LinearLayoutManager.VERTICAL, false);
selectedContacsRV.setLayoutManager(sLayoutManager);
selectedContacsRV.setAdapter(selectedContactsAdapter);
selectedContacsRV.setHasFixedSize(true);
// Initisialize the adapter with the correct contacts (ContactsFilter.SELECTED)
selectedContactsAdapter.getFilter().filter(FilterableContactsAdapter.ContactsFilter.SELECTED, new Filter.FilterListener() {
@Override
public void onFilterComplete(int count) {
onLoadFinish();
}
});
}
}
以下是我正在谈论的一些照片:
我有一个联系人select在这里:
我在这里有两个联系人 select("Abuela" 和 "Adela Zapata"):
在这里,在左侧,我取消了select我select编辑的第一个项目(联系人"Abuela")。右侧是所有未selected:
联系人的列表
好吧,经过一周的研究,我终于找到了解决方案...神奇的是,我怀疑 setHasFixedSize(true)
与视图有关,即使项目已更新,也不会调整大小或重新绘制...在我从 2 个适配器配置中删除该行后,一切都运行良好...有趣的是,我在发布问题后几个小时才找到解决方案。
好吧,我有一个管理联系人的应用程序,我使用 2 RecyclerView
来显示未selected 和 selected 的联系人。用户可以 select 和取消 select 联系人。
这是我的场景:
我有两个 RecyclerView
,一个用于管理 selected 联系人,另一个用于管理未 selected 联系人。当用户 select 未 selected 列表中的联系人时,该联系人将从该列表中删除并插入 selected 列表。如果用户 select 来自 selected 列表的联系人,也会发生同样的情况,只是该联系人从 selected 列表中删除并插入未selected 列表.我实现了自定义 RadioButton
,在 onCheckedChanged
事件中,当 selected 或 unselected.
[= 时,我从适当的适配器中删除了联系人74=]
我有一个适配器用于 selected 列表 (SelectedContactsAdapter
) 和另一个用于未 selected 列表 (UnselectedContactsAdapter
)。我使用新的 SortedList
集合来管理适配器的数据,并在 SortedList
的回调中通知适配器更改并发送回调消息以更新另一个适配器。
例如,如果用户 select 未 selected 列表中的联系人,在 onCheckedChanged
事件中,我会先保存联系人,然后再将其从适配器中删除(我这样做这是因为我需要将它传递给回调,以便它可以插入另一个适配器),然后我从适配器中删除该联系人。这会触发 SortedList
的 onRemoved
方法,然后我调用 notifyItemRemoved(position)
(position
是已删除联系人的位置)和回调以将该联系人插入 select编辑列表。
出于某种原因,notify* 方法不会更新 RecyclerView
视图。我尝试使用 notifyDataSetChanged
并且它有效,但它不是我的选择,因为我需要快速更新,几乎是即时的。
我用 setNestedScrollingEnabled(false)
启动了 2 个 RecyclerView
用于 FastScroll。以防万一...
这是我的代码:
public abstract class FilterableContactsAdapter extends RecyclerView.Adapter<FilterableContactsAdapter.ContactViewHolder>
implements Filterable {
//... Some variables like the filter
protected Contact mLastContactTouched;
protected SortedList<Contact> mFilteredContacts;
protected ContactCallback mContactCallback;
protected boolean mPropagate;
public FilterableContactsAdapter() {
mPropagate = true;
mFilteredContacts = new SortedList<>(Contact.class, new SortedList.Callback<Contact>() {
@Override
public int compare(Contact o1, Contact o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
@Override
public void onChanged(int position, int count) {
notifyItemChanged(position);
if(mContactCallback != null && mPropagate) mContactCallback.onContactChanged(mLastContactTouched, position);
}
@Override
public boolean areContentsTheSame(Contact oldItem, Contact newItem) {
boolean sameIds = (oldItem.getId() == newItem.getId());
boolean sameNames = oldItem.getName().equals(newItem.getName());
boolean samePhoneNumbers = oldItem.getNormalizedPhoneNumber().equals(newItem.getNormalizedPhoneNumber());
if(sameIds && sameNames && samePhoneNumbers) return true;
else return false;
}
@Override
public boolean areItemsTheSame(Contact item1, Contact item2) {
return item1.getId() == item2.getId();
}
@Override
public void onInserted(int position, int count) {
notifyItemInserted(position);
/*if(FilterableContactsAdapter.this instanceof SelectedContactsAdapter) notifyDataSetChanged();
else notifyItemInserted(position);*/
if(mContactCallback != null && mPropagate) mContactCallback.onContactInserted(mLastContactTouched, position);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRemoved(position);
/*if(FilterableContactsAdapter.this instanceof SelectedContactsAdapter) notifyDataSetChanged();
else notifyItemRemoved(position);*/
if(mContactCallback != null && mPropagate) mContactCallback.onContactRemoved(mLastContactTouched, position);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
if(mContactCallback != null && mPropagate) mContactCallback.onContactMoved(mLastContactTouched, fromPosition, toPosition);
}
});
}
public void add(Contact contact) {
mFilteredContacts.add(contact);
}
public void remove(Contact contact) {
mFilteredContacts.remove(contact);
}
//... Some other methods like onCreateViewHolder, the ContactViewHolder declaration and the filter implementation
}
public interface ContactCallback {
void onContactInserted(Contact contact, int adapterPosition);
void onContactRemoved(Contact contact, int adapterPosition);
void onContactMoved(Contact contact, int from, int to);
void onContactChanged(Contact contact, int adapterPosition);
}
public class SelectedContactsAdapter extends FilterableContactsAdapter {
@Override
public void onBindViewHolder(final ContactViewHolder holder, final int position) {
final Contact contact = mFilteredContacts.get(position);
if(contact != null) {
holder.parentLayout.setVisibility(View.VISIBLE);
holder.nameTV.setText(contact.getName());
holder.phoneNumberTV.setText(contact.getNormalizedPhoneNumber());
holder.selectCB.setSafeCheck(true, SafeCheckBox.IGNORE);
holder.selectCB.setOnSafeCheckedListener(new SafeCheckBox.OnSafeCheckedListener() {
@Override
public void onAlwaysCalledListener(CompoundButton buttonView, boolean isChecked) {
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
contact.setSelected(isChecked);
mLastContactTouched = contact;
remove(contact);
}
});
} else {
holder.parentLayout.setVisibility(View.GONE);
}
}
}
public class UnselectedContactsAdapter extends FilterableContactsAdapter {
@Override
public void onBindViewHolder(final ContactViewHolder holder, final int position) {
final Contact contact = mFilteredContacts.get(position);
if(!contact.isSelected()) {
holder.parentLayout.setVisibility(View.VISIBLE);
holder.nameTV.setText(contact.getName());
holder.phoneNumberTV.setText(contact.getNormalizedPhoneNumber());
holder.selectCB.setSafeCheck(false, SafeCheckBox.IGNORE);
holder.selectCB.setOnSafeCheckedListener(new SafeCheckBox.OnSafeCheckedListener() {
@Override
public void onAlwaysCalledListener(CompoundButton buttonView, boolean isChecked) {
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
contact.setSelected(isChecked);
mLastContactTouched = contact;
remove(contact);
}
});
} else {
holder.parentLayout.setVisibility(View.GONE);
}
}
}
public class ContactsActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// init the views and setup the searchbar
setupMultiContactsPicker();
}
//... Some other stuff like an OnClick implementation and
//other utility methods that only manage visibility of some
//components of the UI like 2 TextViews and a ProgressBar
private void setupMultiContactsPicker() {
final Filter.FilterListener filterListener = new Filter.FilterListener() {
@Override
public void onFilterComplete(int count) {
progressBar.setVisibility(View.GONE);
updateLayout();
}
};
unselectedContactsAdapter = new UnselectedContactsAdapter();
unselectedContactsAdapter.setContactCallback(new ContactCallback() {
@Override
public void onContactInserted(Contact contact, int adapterPosition) {
selectedContactsAdapter.setPropagate(false);
if(selectedContactsAdapter.getItemCount() > 0) selectedContactsAdapter.remove(contact);
selectedContactsAdapter.setPropagate(true);
updateLayout();
}
@Override
public void onContactRemoved(Contact contact, int adapterPosition) {
selectedContactsAdapter.setPropagate(false);
selectedContactsAdapter.add(contact);
selectedContactsAdapter.setPropagate(true);
updateLayout();
}
@Override
public void onContactMoved(Contact contact, int from, int to) {
}
@Override
public void onContactChanged(Contact contact, int adapterPosition) {
}
});
unselectedContacsRV.setVisibility(View.VISIBLE);
LinearLayoutManager uLayoutManager = new LinearLayoutManager(ContactsActivity.this, LinearLayoutManager.VERTICAL, false);
unselectedContacsRV.setLayoutManager(uLayoutManager);
unselectedContacsRV.setAdapter(unselectedContactsAdapter);
unselectedContacsRV.setHasFixedSize(true);
// Initisialize the adapter with the correct contacts (ContactsFilter.UNSELECTED)
unselectedContactsAdapter.getFilter().filter(FilterableContactsAdapter.ContactsFilter.UNSELECTED, new Filter.FilterListener() {
@Override
public void onFilterComplete(int count) {
onLoadFinish(); //This method call updateLayout(); when the 2 filters finish to load data into the adapters.
}
});
selectedContactsAdapter = new SelectedContactsAdapter();
selectedContactsAdapter.setContactCallback(new ContactCallback() {
@Override
public void onContactInserted(Contact contact, int adapterPosition) {
unselectedContactsAdapter.setPropagate(false);
if(unselectedContactsAdapter.getItemCount() > 0) unselectedContactsAdapter.remove(contact);
unselectedContactsAdapter.setPropagate(true);
updateLayout(); // This method show or hide some TextViews that I use as section titles, nothing more
}
@Override
public void onContactRemoved(Contact contact, int adapterPosition) {
unselectedContactsAdapter.setPropagate(false);
unselectedContactsAdapter.add(contact);
unselectedContactsAdapter.setPropagate(true);
updateLayout(); // This method show or hide some TextViews that I use as section titles, nothing more
}
@Override
public void onContactMoved(Contact contact, int from, int to) {
}
@Override
public void onContactChanged(Contact contact, int adapterPosition) {
}
});
LinearLayoutManager sLayoutManager = new LinearLayoutManager(ContactsActivity.this, LinearLayoutManager.VERTICAL, false);
selectedContacsRV.setLayoutManager(sLayoutManager);
selectedContacsRV.setAdapter(selectedContactsAdapter);
selectedContacsRV.setHasFixedSize(true);
// Initisialize the adapter with the correct contacts (ContactsFilter.SELECTED)
selectedContactsAdapter.getFilter().filter(FilterableContactsAdapter.ContactsFilter.SELECTED, new Filter.FilterListener() {
@Override
public void onFilterComplete(int count) {
onLoadFinish();
}
});
}
}
以下是我正在谈论的一些照片:
我有一个联系人select在这里:
我在这里有两个联系人 select("Abuela" 和 "Adela Zapata"):
在这里,在左侧,我取消了select我select编辑的第一个项目(联系人"Abuela")。右侧是所有未selected:
联系人的列表
好吧,经过一周的研究,我终于找到了解决方案...神奇的是,我怀疑 setHasFixedSize(true)
与视图有关,即使项目已更新,也不会调整大小或重新绘制...在我从 2 个适配器配置中删除该行后,一切都运行良好...有趣的是,我在发布问题后几个小时才找到解决方案。