过滤由视图模型的 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 方法过滤的目的。