【问题标题】:RecyclerView: wrong position in filtered ListRecyclerView:过滤列表中的错误位置
【发布时间】:2018-02-12 02:31:09
【问题描述】:

我有一个 CardView 项目的 RecyclerView 列表。然后,我使用带有 SearchView 小部件的简单过滤器方法来过滤列表。然后,当我单击过滤后的 CardView 以启动 CardViewDetails 活动时,UI 显示的是原始列表中的 CardView,而不是过滤后的列表。例如,我在原始列表中有一个包含 20 个项目的列表。当我输入搜索约束时,过滤后的列表在 RecyclerView 中正确显示了三个 CardView。当我单击 List 中的第三个 CardView 时,UI 从原始 List 中返回第三个 CardView,而不是从过滤后的 List 中返回第三个 CardView。我在这里错过了什么?

Adapter:

public class MyRecylerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private List<ListItem> mListItems, filteredList;
Context mContext;
private RecyclerItemClickListener recyclerItemClickListener;
private RecyclerView mRecyclerView;
/**********************************************************/
private String searchString = "";
/**********************************************************/

public MyRecylerAdapter(Context context, List<ListItem> listItems) {
    this.mContext = context;
    this.mListItems = listItems;
    this.filteredList = new ArrayList<>();
    this.filteredList.addAll(this.mListItems);
}

// RecyclerItemClickListener is the public interface file used to reach the MainActivity
public void setOnItemClickListener(RecyclerItemClickListener recyclerItemClickListener) {
    this.recyclerItemClickListener = recyclerItemClickListener;
}

// Get the Item's position.
public ListItem getItem(int position) {
    return filteredList.get(position);
}

@Override
public int getItemCount() {
    if (filteredList.size() >0) {
        return filteredList.size();
    }
    else {
        return mListItems.size();
    }
}

public void setFilter(List<ListItem> listItems, String searchString) {
    // Note: the String is to get s.toString() from the Main Activity SearchView.
    filteredList = new ArrayList<>();
    filteredList.addAll(listItems);
    this.searchString = searchString;
    notifyDataSetChanged();
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false);
    final ItemHolder itemHolder = new ItemHolder(view);

        // Attach a Click listener to the items's (row) view.
        // itemView is from the ItemHolder() below.
        // onItemClick is the click method in MainActivity.
        itemHolder.itemView.setOnClickListener(new View.OnClickListener() {                
            @Override
            public void onClick(View view) {

                int adapterPos = itemHolder.getAdapterPosition(); // get the item position.                    
                if (adapterPos != RecyclerView.NO_POSITION) {
                    if (recyclerItemClickListener != null) {
                        // pass the item to the Main Activity
                        // through the RecyclerItemClickListener file and its
                        // public interface.
                        recyclerItemClickListener.onItemClick(itemHolder.itemView,adapterPos);
                    }
                }
            }
        });            
    return itemHolder;
}

private static class ItemHolder extends RecyclerView.ViewHolder {

    private TextView cardBlankText2; 

    private ItemHolder(View itemView) {
        super(itemView);

        cardBlankText2 = (TextView) itemView.findViewById(R.id.cardBlankText2);            
}

public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {

    final ListItem listItem = filteredList.get(position);
    final ItemHolder itemHolder = (ItemHolder) holder;

    itemHolder.cardBlankText2.setText(listItem.getTodo());
}

Activity:

public class MainActivity extends AppCompatActivity implements
    RecyclerItemClickListener {

private List<ListItem> allList = new ArrayList<>();
private RecyclerView mRecyclerView;
private SQLiteDB sqLiteDB;
private MyRecylerAdapter adapter;    
private CardView cardview;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    sqLiteDB = SQLiteDB.getInstance(this);        
    mRecyclerView = (RecyclerView)findViewById(R.id.list_recyclerview);        
    final LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);        
    mRecyclerView.setLayoutManager(layoutManager);
    allList = sqLiteDB.getAllDBItems();

    adapter = new MyRecylerAdapter(this, allList);
    adapter.setOnItemClickListener(this);
    mRecyclerView.setAdapter(adapter);
}

@Override
public void onItemClick(View view, int position) {
    cardview = (CardView) view;
    cardview.setEnabled(false);

    // Create a new intent to send data from this MainActivity to the CardViewDetails
    // Activity.
    Intent intent = new Intent(this,CardViewDetails.class);
    ListItem listItem = adapter.getItem(position);
    // Add the item object to the Intent.  The item object can be used because the
    // model class implements Parcelable so it holds all of the getters
    // that can be snagged in the next Activity with the
    // getParcelableExtra method.
    intent.putExtra("item",listItem);
    intent.putExtra("position",position);
    startActivity(intent);
    finish();
}

// SearchView
final EditText mSearchEditText = (EditText) mSearchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);

    mSearchEditText.addTextChangedListener(new TextWatcher() {

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {

             final ArrayList<ListItem> filteredModelList = filter(allList, s.toString());

                if (!mSearchView.isIconified() && filteredModelList.size() == 0) {
                    Toast.makeText(MainActivity.this, "Not Found", Toast.LENGTH_SHORT).show();
                    // re-load the list so the Adapter refreshes the RecyclerView list View.
                    adapter.clear();
                    adapter.addAll(allList);
                } else if (!mSearchView.isIconified() && filteredModelList.size() > 0) {                            
                    adapter.setFilter(filteredModelList, s.toString());
                    mRecyclerView.scrollToPosition(0);
                }
            }
        }
    });

private ArrayList<ListItem> filter(List<ListItem> models, String query) {

    query = query.toLowerCase();

    final ArrayList<ListItem> filteredModelList = new ArrayList<>();
    for (ListItem listItem : models) {
        final String text = listItem.getTodo().toLowerCase();
        final String text2 = listItem.getNote1().toLowerCase();
        final String text3 = listItem.getNote2().toLowerCase();
        if (text.contains(query) || text2.contains(query) ||
            text3.contains(query)) {
            filteredModelList.add(listItem);
        }
    }
    return filteredModelList;
}

RecyclerItemClickListener:

public interface RecyclerItemClickListener {

    void onItemClick(View view, int position);
}

CardViewDetails:

public class CardViewDetails extends AppCompatActivity {

private int position;
private SQLiteDB helper;
List<ListItem> listItems;
private CardView cardview;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_details);

    final CardView cardView = (CardView) findViewById(R.id.dets);

    // Create a variable for the skychill footer text.
    final TextView skychilltext5;

    // A db helper instance is needed for the removeItem() below
    // when the user Longclicks the skycard for deletion.
    helper = new SQLiteDB(this);

    // Get the position of the clicked on R. list CardView from
    // the MainActivity's intent bundle.
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
        // get the CardView item using the int position from the
        // MainActivity's onItemClick() and the putExtra in the intent.
        position = extras.getInt("position",0); // 0 is default value
    }

    cb2 = (TextView) findViewById(R.id.cb2);

    helper = new SQLiteDB(this);
    listItems = new ArrayList<>();
    listItems = helper.getAllDBItems(); 

    cb2.setText(listItems.get(position).getTodo());

    ...

}   

【问题讨论】:

  • 当将点击事件传递给 MainActivity 时,MainActivity 可能仍然使用“旧的”未过滤列表而不是过滤列表来确定要操作的项目?
  • @Ascorbin 可能是这样。我被困在如何解决问题上。有什么想法吗?
  • 可能有,如果您发布 MainActivity 的相关部分;)
  • 我发布了 MainActivity 的 onCreate 和 onItemClick 方法。我可以添加 Model 类和 DetailsActivity。
  • 我怀疑,在 viewHolder 上设置 clickListener 时,使用 getAdapterPosition 检索位置并不是您想要的。可以尝试在 onBindViewHolder 中设置 clickListener 并使用 onBindViewHolder 方法参数的位置而不是使用 getAdapterPosition 吗?

标签: android android-recyclerview onclicklistener


【解决方案1】:

应用过滤器后,sql DB (getAllDBItems) 数据保持不变。您仅将 position 传递给 CardViewDetail。并且sql数据是原始列表。

您应该将您的 ListItem as parcelable 传递给CardViewDetails 而不是位置。你的问题会得到解决的。

【讨论】:

  • 非常好,完全符合我的要求。我正在努力解决的最后一个问题是如何在用户编辑数据时更新 CardViewDetails 上的视图。我在这里提出了一个新问题:stackoverflow.com/questions/46046633/…我将不胜感激有关如何解决的任何想法或想法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-19
  • 1970-01-01
  • 2020-12-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
相关资源
最近更新 更多