You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android RecyclerView长按Item弹出PopupMenu(position=10时)报错求助

解决RecyclerView长按Item弹出PopupMenu在position=10时的报错问题

我来帮你分析并解决这个问题:

问题根源

你当前用binding.rcvPrefix.getChildAt(position)获取PopupMenu的锚点View,但这个方法有个容易踩的坑:RecyclerView的getChildAt(int index)参数是「可见区域内子View的索引」,而非数据源的position。当position=10时,这个Item大概率不在屏幕可见范围内,getChildAt(10)会返回null,导致PopupMenu没有有效锚点,直接抛出IllegalStateException: MenuPopupHelper cannot be used without an anchor异常。

解决方案:直接传递长按的Item View作为锚点

最可靠的方式是在Adapter的长按监听里,直接把被长按的Item View传给Activity的回调,而不是通过position去RecyclerView里找View。

1. 修改Adapter中的长按回调逻辑

在你的AdapterRcvPrefix里,把长按的View一起传递给Activity:

// Adapter中的Item长按监听
itemView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        // 传递当前被长按的View和对应的position
        listener.onRecyclerViewItemLongClicked(getAdapterPosition(), v);
        return true;
    }
});

同时记得更新你的回调接口定义,添加View参数:

public interface OnItemLongClickListener {
    void onRecyclerViewItemLongClicked(int position, View anchorView);
}

2. 修改Activity中的方法实现

把原来的id参数替换为View anchorView,直接用这个View作为PopupMenu的锚点:

public void onRecyclerViewItemLongClicked(final int position, View anchorView) {
    // 直接用传递过来的锚点View创建PopupMenu
    PopupMenu popup = new PopupMenu(MainActivity.this, anchorView);
    popup.getMenuInflater().inflate(R.menu.menu_item_rcv, popup.getMenu());
    popup.show();
    
    popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            switch (item.getItemId()){
                case R.id.item_add:
                    createDialogAdd();
                    initializeRCV();
                    Toast.makeText(MainActivity.this, "Add", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.item_edit:
                    Toast.makeText(MainActivity.this, "Edit", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.item_delete:
                    Toast.makeText(MainActivity.this, "Delete", Toast.LENGTH_SHORT).show();
                    db.deletePrefix(prefixList.get(position));
                    prefixList.remove(position);
                    initializeRCV();
                    break;
                default:
                    break;
            }
            return true;
        }
    });
}

额外提示

  • 建议用getAdapterPosition()而非直接用position,避免Item刷新后位置错乱的问题。
  • 如果确实需要通过position获取View,可以用RecyclerView的findViewHolderForAdapterPosition(int position)方法,它会返回对应position的ViewHolder(即使Item不可见也能返回,但如果Item被回收了会返回null),不过还是直接传递View的方式最稳妥。

内容的提问来源于stack exchange,提问作者Lê Hồng Huy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:37:49