过滤由视图模型的 LiveData 条目填充的回收器视图
Filter recycler view populated by view model's LiveData entries
我正在使用架构组件视图模型的 LiveData 来填充回收器视图,并想添加一个搜索视图过滤器,但找不到任何解决方案。
我尝试在适配器中使用可过滤接口,但它也不起作用,可能是因为视图模型不允许它更改。
我的适配器是-
public class NetworkAdapter extends RecyclerView.Adapter<NetworkAdapter.NetworksViewHolder> implements Filterable {
// Member variable to handle item clicks
final private ItemClickListener mItemClickListener;
// Class variables for the List that holds task data and the Context
private List<NetworkEntry> mNetworkEntries;
private List<NetworkEntry> mFilteredNetworkEntries = new ArrayList<>();
private Context mContext;
/**
* Constructor for the TaskAdapter that initializes the Context.
*
* @param context the current Context
* @param listener the ItemClickListener
*/
public NetworkAdapter(Context context, ItemClickListener listener) {
mContext = context;
mItemClickListener = listener;
}
/**
* Called when ViewHolders are created to fill a RecyclerView.
*
* @return A new TaskViewHolder that holds the view for each task
*/
@Override
public NetworksViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Inflate the task_layout to a view
View view = LayoutInflater.from(mContext)
.inflate(R.layout.network_list_item, parent, false);
return new NetworksViewHolder(view);
}
/**
* Called by the RecyclerView to display data at a specified position in the Cursor.
*
* @param holder The ViewHolder to bind Cursor data to
* @param position The position of the data in the Cursor
*/
@Override
public void onBindViewHolder(NetworksViewHolder holder, int position) {
// Determine the values of the wanted data
holder.onBindData(position);
}
/**
* Returns the number of items to display.
*/
@Override
public int getItemCount() {
if (mNetworkEntries == null) {
return 0;
}
return mNetworkEntries.size();
}
/**
* When data changes, this method updates the list of taskEntries
* and notifies the adapter to use the new values on it
*/
public void setNetworks(List<NetworkEntry> networkEntries) {
mNetworkEntries = networkEntries;
mFilteredNetworkEntries.addAll(mNetworkEntries);
notifyDataSetChanged();
}
public List<NetworkEntry> getNetworks() {
return mNetworkEntries;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
mFilteredNetworkEntries = mNetworkEntries;
} else {
List<NetworkEntry> filteredList = new ArrayList<>();
for (NetworkEntry row : mNetworkEntries) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getNetworkName().toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(row);
}
}
mFilteredNetworkEntries = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = mFilteredNetworkEntries;
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mFilteredNetworkEntries = (ArrayList<NetworkEntry>) filterResults.values;
notifyDataSetChanged();
}
};
}
public interface ItemClickListener {
void onItemClickListener(NetworkData networkData);
}
public class NetworksViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView networkLogoImageView;
TextView networkNameTextView;
TextView joinTextView;
TextView commissionTextView;
TextView minPayTextView;
TextView payFrequencyTextView;
TextView offerTextView;
TextView likeTextView;
View containerView;
public NetworksViewHolder(View itemView) {
super(itemView);
networkLogoImageView = (ImageView) itemView.findViewById(R.id.iv_logo);
networkNameTextView = (TextView) itemView.findViewById(R.id.tv_network_name);
joinTextView = (TextView) itemView.findViewById(R.id.bt_join);
commissionTextView = (TextView) itemView.findViewById(R.id.iv_commission);
minPayTextView = (TextView) itemView.findViewById(R.id.tv_min_pay);
payFrequencyTextView = (TextView) itemView.findViewById(R.id.tv_pay_frequency);
offerTextView = (TextView) itemView.findViewById(R.id.iv_offers);
likeTextView = (TextView) itemView.findViewById(R.id.iv_likes);
containerView = itemView.findViewById(R.id.layoutContainer);
joinTextView.setOnClickListener(this);
containerView.setOnClickListener(this);
}
public void onBindData(int position) {
NetworkEntry networkEntry = mNetworkEntries.get(getAdapterPosition());
Picasso.with(mContext).load(networkEntry.getNetworkImageUrl()).into(networkLogoImageView);
networkNameTextView.setText(networkEntry.getNetworkName());
commissionTextView.setText(networkEntry.getNetworkCommission());
minPayTextView.setText(mContext.getString(R.string.tv_min_pay, networkEntry.getNetworkMinPay()));
payFrequencyTextView.setText(networkEntry.getNetworkPayFrequency());
offerTextView.setText(networkEntry.getNetworkOffers());
}
@Override
public void onClick(View view) {
int adapterPosition = getAdapterPosition();
NetworkEntry networkEntry = mNetworkEntries.get(adapterPosition);
if (view.getId() == R.id.bt_join) {
AppUtilities.openWebPage(mContext, networkEntry.getNetworkJoinUrl());
} else {
NetworkData networkData = new NetworkData(networkEntry);
Log.v(NetworkAdapter.class.getSimpleName(), "Network SNO : " + networkData.getSno());
mItemClickListener.onItemClickListener(networkData);
}
}
}
}
并且搜索视图 OnQueryTextListener 为 -
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.search_menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
searchView.setQueryHint("Search");
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onQueryTextSubmit(String query) {
adapter.getFilter().filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
出现问题是因为您应该在适配器中使用 FilteredList,而不是原始列表:
public class NetworkAdapter extends RecyclerView.Adapter<NetworkAdapter.NetworksViewHolder> implements Filterable {
// Member variable to handle item clicks
final private ItemClickListener mItemClickListener;
// Class variables for the List that holds task data and the Context
private List<NetworkEntry> mNetworkEntries;
private List<NetworkEntry> mFilteredNetworkEntries = new ArrayList<>();
private Context mContext;
/**
* Constructor for the TaskAdapter that initializes the Context.
*
* @param context the current Context
* @param listener the ItemClickListener
*/
public NetworkAdapter(Context context, ItemClickListener listener) {
mContext = context;
mItemClickListener = listener;
}
/**
* Called when ViewHolders are created to fill a RecyclerView.
*
* @return A new TaskViewHolder that holds the view for each task
*/
@Override
public NetworksViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Inflate the task_layout to a view
View view = LayoutInflater.from(mContext)
.inflate(R.layout.network_list_item, parent, false);
return new NetworksViewHolder(view);
}
/**
* Called by the RecyclerView to display data at a specified position in the Cursor.
*
* @param holder The ViewHolder to bind Cursor data to
* @param position The position of the data in the Cursor
*/
@Override
public void onBindViewHolder(NetworksViewHolder holder, int position) {
// Determine the values of the wanted data
holder.onBindData(position);
}
/**
* Returns the number of items to display.
*/
@Override
public int getItemCount() {
if (mFilteredNetworkEntries == null) {
return 0;
}
return mFilteredNetworkEntries.size();
}
/**
* When data changes, this method updates the list of taskEntries
* and notifies the adapter to use the new values on it
*/
public void setNetworks(List<NetworkEntry> networkEntries) {
mNetworkEntries = networkEntries;
mFilteredNetworkEntries.addAll(mNetworkEntries);
notifyDataSetChanged();
}
public List<NetworkEntry> getNetworks() {
return mFilteredNetworkEntries;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
List<NetworkEntry> filteredList = new ArrayList<>();
if (charString.isEmpty()) {
filteredList = mNetworkEntries;
} else {
for (NetworkEntry row : mNetworkEntries) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getNetworkName().toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(row);
}
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = filteredList;
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mFilteredNetworkEntries = (ArrayList<NetworkEntry>) filterResults.values;
notifyDataSetChanged();
}
};
}
public interface ItemClickListener {
void onItemClickListener(NetworkData networkData);
}
public class NetworksViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView networkLogoImageView;
TextView networkNameTextView;
TextView joinTextView;
TextView commissionTextView;
TextView minPayTextView;
TextView payFrequencyTextView;
TextView offerTextView;
TextView likeTextView;
View containerView;
public NetworksViewHolder(View itemView) {
super(itemView);
networkLogoImageView = (ImageView) itemView.findViewById(R.id.iv_logo);
networkNameTextView = (TextView) itemView.findViewById(R.id.tv_network_name);
joinTextView = (TextView) itemView.findViewById(R.id.bt_join);
commissionTextView = (TextView) itemView.findViewById(R.id.iv_commission);
minPayTextView = (TextView) itemView.findViewById(R.id.tv_min_pay);
payFrequencyTextView = (TextView) itemView.findViewById(R.id.tv_pay_frequency);
offerTextView = (TextView) itemView.findViewById(R.id.iv_offers);
likeTextView = (TextView) itemView.findViewById(R.id.iv_likes);
containerView = itemView.findViewById(R.id.layoutContainer);
joinTextView.setOnClickListener(this);
containerView.setOnClickListener(this);
}
public void onBindData(int position) {
NetworkEntry networkEntry = mFilteredNetworkEntries.get(getAdapterPosition());
Picasso.with(mContext).load(networkEntry.getNetworkImageUrl()).into(networkLogoImageView);
networkNameTextView.setText(networkEntry.getNetworkName());
commissionTextView.setText(networkEntry.getNetworkCommission());
minPayTextView.setText(mContext.getString(R.string.tv_min_pay, networkEntry.getNetworkMinPay()));
payFrequencyTextView.setText(networkEntry.getNetworkPayFrequency());
offerTextView.setText(networkEntry.getNetworkOffers());
}
@Override
public void onClick(View view) {
int adapterPosition = getAdapterPosition();
NetworkEntry networkEntry = mFilteredNetworkEntries.get(adapterPosition);
if (view.getId() == R.id.bt_join) {
AppUtilities.openWebPage(mContext, networkEntry.getNetworkJoinUrl());
} else {
NetworkData networkData = new NetworkData(networkEntry);
Log.v(NetworkAdapter.class.getSimpleName(), "Network SNO : " + networkData.getSno());
mItemClickListener.onItemClickListener(networkData);
}
}
}
}
想法是在您的适配器中使用过滤列表,原始列表在适配器中仅用于被 performFiltering
方法过滤的目的。
我正在使用架构组件视图模型的 LiveData 来填充回收器视图,并想添加一个搜索视图过滤器,但找不到任何解决方案。 我尝试在适配器中使用可过滤接口,但它也不起作用,可能是因为视图模型不允许它更改。
我的适配器是-
public class NetworkAdapter extends RecyclerView.Adapter<NetworkAdapter.NetworksViewHolder> implements Filterable {
// Member variable to handle item clicks
final private ItemClickListener mItemClickListener;
// Class variables for the List that holds task data and the Context
private List<NetworkEntry> mNetworkEntries;
private List<NetworkEntry> mFilteredNetworkEntries = new ArrayList<>();
private Context mContext;
/**
* Constructor for the TaskAdapter that initializes the Context.
*
* @param context the current Context
* @param listener the ItemClickListener
*/
public NetworkAdapter(Context context, ItemClickListener listener) {
mContext = context;
mItemClickListener = listener;
}
/**
* Called when ViewHolders are created to fill a RecyclerView.
*
* @return A new TaskViewHolder that holds the view for each task
*/
@Override
public NetworksViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Inflate the task_layout to a view
View view = LayoutInflater.from(mContext)
.inflate(R.layout.network_list_item, parent, false);
return new NetworksViewHolder(view);
}
/**
* Called by the RecyclerView to display data at a specified position in the Cursor.
*
* @param holder The ViewHolder to bind Cursor data to
* @param position The position of the data in the Cursor
*/
@Override
public void onBindViewHolder(NetworksViewHolder holder, int position) {
// Determine the values of the wanted data
holder.onBindData(position);
}
/**
* Returns the number of items to display.
*/
@Override
public int getItemCount() {
if (mNetworkEntries == null) {
return 0;
}
return mNetworkEntries.size();
}
/**
* When data changes, this method updates the list of taskEntries
* and notifies the adapter to use the new values on it
*/
public void setNetworks(List<NetworkEntry> networkEntries) {
mNetworkEntries = networkEntries;
mFilteredNetworkEntries.addAll(mNetworkEntries);
notifyDataSetChanged();
}
public List<NetworkEntry> getNetworks() {
return mNetworkEntries;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
mFilteredNetworkEntries = mNetworkEntries;
} else {
List<NetworkEntry> filteredList = new ArrayList<>();
for (NetworkEntry row : mNetworkEntries) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getNetworkName().toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(row);
}
}
mFilteredNetworkEntries = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = mFilteredNetworkEntries;
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mFilteredNetworkEntries = (ArrayList<NetworkEntry>) filterResults.values;
notifyDataSetChanged();
}
};
}
public interface ItemClickListener {
void onItemClickListener(NetworkData networkData);
}
public class NetworksViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView networkLogoImageView;
TextView networkNameTextView;
TextView joinTextView;
TextView commissionTextView;
TextView minPayTextView;
TextView payFrequencyTextView;
TextView offerTextView;
TextView likeTextView;
View containerView;
public NetworksViewHolder(View itemView) {
super(itemView);
networkLogoImageView = (ImageView) itemView.findViewById(R.id.iv_logo);
networkNameTextView = (TextView) itemView.findViewById(R.id.tv_network_name);
joinTextView = (TextView) itemView.findViewById(R.id.bt_join);
commissionTextView = (TextView) itemView.findViewById(R.id.iv_commission);
minPayTextView = (TextView) itemView.findViewById(R.id.tv_min_pay);
payFrequencyTextView = (TextView) itemView.findViewById(R.id.tv_pay_frequency);
offerTextView = (TextView) itemView.findViewById(R.id.iv_offers);
likeTextView = (TextView) itemView.findViewById(R.id.iv_likes);
containerView = itemView.findViewById(R.id.layoutContainer);
joinTextView.setOnClickListener(this);
containerView.setOnClickListener(this);
}
public void onBindData(int position) {
NetworkEntry networkEntry = mNetworkEntries.get(getAdapterPosition());
Picasso.with(mContext).load(networkEntry.getNetworkImageUrl()).into(networkLogoImageView);
networkNameTextView.setText(networkEntry.getNetworkName());
commissionTextView.setText(networkEntry.getNetworkCommission());
minPayTextView.setText(mContext.getString(R.string.tv_min_pay, networkEntry.getNetworkMinPay()));
payFrequencyTextView.setText(networkEntry.getNetworkPayFrequency());
offerTextView.setText(networkEntry.getNetworkOffers());
}
@Override
public void onClick(View view) {
int adapterPosition = getAdapterPosition();
NetworkEntry networkEntry = mNetworkEntries.get(adapterPosition);
if (view.getId() == R.id.bt_join) {
AppUtilities.openWebPage(mContext, networkEntry.getNetworkJoinUrl());
} else {
NetworkData networkData = new NetworkData(networkEntry);
Log.v(NetworkAdapter.class.getSimpleName(), "Network SNO : " + networkData.getSno());
mItemClickListener.onItemClickListener(networkData);
}
}
}
}
并且搜索视图 OnQueryTextListener 为 -
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.search_menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
searchView.setQueryHint("Search");
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onQueryTextSubmit(String query) {
adapter.getFilter().filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText);
return false;
}
出现问题是因为您应该在适配器中使用 FilteredList,而不是原始列表:
public class NetworkAdapter extends RecyclerView.Adapter<NetworkAdapter.NetworksViewHolder> implements Filterable {
// Member variable to handle item clicks
final private ItemClickListener mItemClickListener;
// Class variables for the List that holds task data and the Context
private List<NetworkEntry> mNetworkEntries;
private List<NetworkEntry> mFilteredNetworkEntries = new ArrayList<>();
private Context mContext;
/**
* Constructor for the TaskAdapter that initializes the Context.
*
* @param context the current Context
* @param listener the ItemClickListener
*/
public NetworkAdapter(Context context, ItemClickListener listener) {
mContext = context;
mItemClickListener = listener;
}
/**
* Called when ViewHolders are created to fill a RecyclerView.
*
* @return A new TaskViewHolder that holds the view for each task
*/
@Override
public NetworksViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Inflate the task_layout to a view
View view = LayoutInflater.from(mContext)
.inflate(R.layout.network_list_item, parent, false);
return new NetworksViewHolder(view);
}
/**
* Called by the RecyclerView to display data at a specified position in the Cursor.
*
* @param holder The ViewHolder to bind Cursor data to
* @param position The position of the data in the Cursor
*/
@Override
public void onBindViewHolder(NetworksViewHolder holder, int position) {
// Determine the values of the wanted data
holder.onBindData(position);
}
/**
* Returns the number of items to display.
*/
@Override
public int getItemCount() {
if (mFilteredNetworkEntries == null) {
return 0;
}
return mFilteredNetworkEntries.size();
}
/**
* When data changes, this method updates the list of taskEntries
* and notifies the adapter to use the new values on it
*/
public void setNetworks(List<NetworkEntry> networkEntries) {
mNetworkEntries = networkEntries;
mFilteredNetworkEntries.addAll(mNetworkEntries);
notifyDataSetChanged();
}
public List<NetworkEntry> getNetworks() {
return mFilteredNetworkEntries;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
List<NetworkEntry> filteredList = new ArrayList<>();
if (charString.isEmpty()) {
filteredList = mNetworkEntries;
} else {
for (NetworkEntry row : mNetworkEntries) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getNetworkName().toLowerCase().contains(charString.toLowerCase())) {
filteredList.add(row);
}
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = filteredList;
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mFilteredNetworkEntries = (ArrayList<NetworkEntry>) filterResults.values;
notifyDataSetChanged();
}
};
}
public interface ItemClickListener {
void onItemClickListener(NetworkData networkData);
}
public class NetworksViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView networkLogoImageView;
TextView networkNameTextView;
TextView joinTextView;
TextView commissionTextView;
TextView minPayTextView;
TextView payFrequencyTextView;
TextView offerTextView;
TextView likeTextView;
View containerView;
public NetworksViewHolder(View itemView) {
super(itemView);
networkLogoImageView = (ImageView) itemView.findViewById(R.id.iv_logo);
networkNameTextView = (TextView) itemView.findViewById(R.id.tv_network_name);
joinTextView = (TextView) itemView.findViewById(R.id.bt_join);
commissionTextView = (TextView) itemView.findViewById(R.id.iv_commission);
minPayTextView = (TextView) itemView.findViewById(R.id.tv_min_pay);
payFrequencyTextView = (TextView) itemView.findViewById(R.id.tv_pay_frequency);
offerTextView = (TextView) itemView.findViewById(R.id.iv_offers);
likeTextView = (TextView) itemView.findViewById(R.id.iv_likes);
containerView = itemView.findViewById(R.id.layoutContainer);
joinTextView.setOnClickListener(this);
containerView.setOnClickListener(this);
}
public void onBindData(int position) {
NetworkEntry networkEntry = mFilteredNetworkEntries.get(getAdapterPosition());
Picasso.with(mContext).load(networkEntry.getNetworkImageUrl()).into(networkLogoImageView);
networkNameTextView.setText(networkEntry.getNetworkName());
commissionTextView.setText(networkEntry.getNetworkCommission());
minPayTextView.setText(mContext.getString(R.string.tv_min_pay, networkEntry.getNetworkMinPay()));
payFrequencyTextView.setText(networkEntry.getNetworkPayFrequency());
offerTextView.setText(networkEntry.getNetworkOffers());
}
@Override
public void onClick(View view) {
int adapterPosition = getAdapterPosition();
NetworkEntry networkEntry = mFilteredNetworkEntries.get(adapterPosition);
if (view.getId() == R.id.bt_join) {
AppUtilities.openWebPage(mContext, networkEntry.getNetworkJoinUrl());
} else {
NetworkData networkData = new NetworkData(networkEntry);
Log.v(NetworkAdapter.class.getSimpleName(), "Network SNO : " + networkData.getSno());
mItemClickListener.onItemClickListener(networkData);
}
}
}
}
想法是在您的适配器中使用过滤列表,原始列表在适配器中仅用于被 performFiltering
方法过滤的目的。