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

使用SearchView与RecyclerView时的数据跳转异常问题

Android全局搜索后跳转数据异常问题

我开发的Android应用包含ViewPager、TabLayout及3个内置RecyclerView的Fragment,需求是通过SearchView对所有Fragment内容做全局搜索,而非仅当前Fragment。但搜索后出现异常:点击第一个搜索结果可正常跳转并携带数据至Buy_Accessories页面,点击第二个结果跳转时无数据传入。注:所有Fragment代码、Adapter逻辑一致,仅Firebase数据库路径不同。


相关代码

ViewpagerActivity

public class Accessories_viewpager extends AppCompatActivity {

ViewpagerMainBinding binding;
ViewPagerAdapter viewPagerAdapter;
ArrayList <Product_Model> allItems = new ArrayList <>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    binding = DataBindingUtil.setContentView(this, R.layout.viewpager_main);

    binding.tvTitle.setText("اكسسوارات");
    getTab();
    binding.btnArrowBack.setOnClickListener(v -> {
        startActivity(new Intent(Accessories_viewpager.this, Nav_Home.class));
        finish();
    });
    binding.btnCart.setOnClickListener(v -> {
        Intent intent = new Intent(Accessories_viewpager.this, Nav_Home.class);
        intent.putExtra("cartId", 2);
        startActivity(intent);
        finish();
    });

    binding.btnSearch.setOnClickListener(v -> {
    });
}

private void getTab() {
    new Handler().post(() -> {
        viewPagerAdapter = new ViewPagerAdapter(this);
        viewPagerAdapter.addFragment(BodyAcc_Fragment.getInstance(),"اكسسوارات جسم");
        viewPagerAdapter.addFragment(HairAcce_Fragment.getInstance(),"اكسسوارات شعر");
        viewPagerAdapter.addFragment(OtherAcce_Fragment.getInstance(),"اكسسوارات اخري");
        binding.viewPagerId.setAdapter(viewPagerAdapter);
        String [] title = new String[]{"اكسسوارات جسم","اكسسوارات شعر","اكسسوارات اخري"};
        new TabLayoutMediator(binding.tabLayoutId,binding.viewPagerId,(((tab, position) -> tab.setText(title[position])))).attach();
        binding.viewPagerId.setOffscreenPageLimit(3);
    });
}
@Override
public void onBackPressed() {
    super.onBackPressed();
    startActivity(new Intent(Accessories_viewpager.this, Nav_Home.class));
    finish();
}
}

Fragment(以BodyAcc_Fragment为例)

public class BodyAcc_Fragment extends Fragment implements RecyclerView_InterFace {
ProductList2Binding binding;
private DatabaseReference db;
FirebaseAuth mAuth;
private ArrayList <Product_Model> list;
private Products2_Adapter adapter;

public static BodyAcc_Fragment getInstance() {
    BodyAcc_Fragment mix_fragment = new BodyAcc_Fragment();
    return mix_fragment;
}

@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    binding = DataBindingUtil.inflate(inflater, R.layout.product_list2, container, false);
    View view = binding.getRoot();

    mAuth = FirebaseAuth.getInstance();
    db = FirebaseDatabase.getInstance().getReference();

    binding.rvHFSD.setHasFixedSize(true);
    binding.rvHFSD.setLayoutManager(new GridLayoutManager(getActivity(),2));

    binding.searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            adapter.getAllItems(((Accessories_viewpager) getActivity()).allItems);
            adapter.getFilter().filter(newText);
            return false;
        }
    });
    binding.nameOfCategoryTv.setText("اكسسوارات الجسم");
    binding.categoryImage.setImageResource(R.drawable.img_accessories1);
    getList();

    return view;
}
private void getList() {
    binding.progressBar.setVisibility(View.VISIBLE);
    db.child("اكسسوارات").child("جسم").addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            binding.progressBar.setVisibility(View.GONE);
            list = new ArrayList <>();
            adapter = new Products2_Adapter(getActivity(), list, BodyAcc_Fragment.this);
            binding.rvHFSD.setAdapter(adapter);
            for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                Product_Model menuModel = dataSnapshot.getValue(Product_Model.class);
                list.add(menuModel);
                adapter.notifyItemInserted(list.size() - 1);
                adapter.getItemCount();
            }
            ((Accessories_viewpager) getActivity()).allItems.addAll(list);
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

@Override
public void onItemClick(int position) {
    Product_Model product_model = list.get(position);
    Intent intent = new Intent(getActivity(), Buy_Accessories.class);
    intent.putExtra("name", product_model.getOilName());
    intent.putExtra("productId", product_model.getProductId());
    intent.putExtra("image", product_model.getImageResource());
    intent.putExtra("category", "جسم");
    startActivity(intent);
    getActivity().finish();
}
}

Products2_Adapter

public class Products2_Adapter extends RecyclerView.Adapter <Products2_Adapter.ViewHolder> implements Filterable {

private Context context;
public List <Product_Model> list;
List<Product_Model> allItems;
private List<Product_Model> menuModelListFilter;
private RecyclerView_InterFace recyclerView_interFace;

public Products2_Adapter(Context context, List <Product_Model> list, RecyclerView_InterFace recyclerView_interFace) {
    this.context = context;
    this.list = list;
    this.recyclerView_interFace = recyclerView_interFace;
    menuModelListFilter = new ArrayList <>(list);
}

@NonNull
@Override
public Products2_Adapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    return new Products2_Adapter.ViewHolder(LayoutInflater.from(parent.getContext())
            .inflate(R.layout.card_menu, parent, false));
}


@Override
public void onBindViewHolder(@NonNull Products2_Adapter.ViewHolder holder, int position) {

    Product_Model menuModel = list.get(position);

    holder.imageName.setText(menuModel.getOilName());
    Picasso.get().load(menuModel.getImageResource()).into(holder.image);
}

@Override
public int getItemCount() {
    return list.size();
}


public class ViewHolder extends RecyclerView.ViewHolder {
    ImageView image;
    TextView imageName;
    CardView parentLayout;

    public ViewHolder(@NonNull View itemView) {
        super(itemView);

        image = itemView.findViewById(R.id.image);
        imageName = itemView.findViewById(R.id.image_name);
        parentLayout = itemView.findViewById(R.id.RelativeLayout);

        itemView.setOnClickListener(view -> recyclerView_interFace.onItemClick(getBindingAdapterPosition()));
    }
}

@Override
public Filter getFilter() {
    return filter;
}
private Filter filter = new Filter() {

    //run on background thread
    @Override
    protected FilterResults performFiltering(CharSequence charSequence) {

        if (menuModelListFilter.size() == 0) menuModelListFilter = new ArrayList<>(list);

        List<Product_Model> filterList = new ArrayList <>();
        if (charSequence ==null || charSequence.length()==0){
            // if search text is empty add all original list values to filter list
            filterList.addAll(menuModelListFilter);
        }else {
            String filterPattern = charSequence.toString().toLowerCase().trim();
            // Perform search on whole original list
            for (Product_Model menu : allItems){
                if (menu.getOilName().toLowerCase().contains(filterPattern)){
                    filterList.add(menu);
                }
            }
        }
        FilterResults results = new FilterResults();
        results.values = filterList;
        return results;
    }


    //run on UI thread
    @Override
    protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
        list.clear();
        list.addAll((List) filterResults.values);
        notifyDataSetChanged();
    }
};

public void getAllItems(List<Product_Model> allData){
    allItems = allData;
}
}

问题根源与修复方案

核心问题

  1. 点击数据来源不匹配:Fragment的onItemClick方法从本地原始列表list中取数据,但搜索过滤后,RecyclerView显示的是Adapter中经过过滤的list集合,两者内容不一致。当搜索结果包含其他Fragment的数据时,当前Fragment的原始列表中没有对应数据,就会出现跳转无数据的情况。
  2. 搜索逻辑冗余:每次搜索文本变化时都重复给Adapter赋值全量数据,可能导致数据混乱;同时Filter逻辑中menuModelListFilter的初始化逻辑存在漏洞,清空搜索时可能无法正确恢复原始数据。

修复步骤

1. 修改点击事件传递逻辑,直接传递数据对象

  • 更新RecyclerView_InterFace接口,改为接收Product_Model对象:
public interface RecyclerView_InterFace {
    void onItemClick(Product_Model product);
}
  • 修改Adapter的ViewHolder点击事件,直接传递当前过滤后的列表项:
itemView.setOnClickListener(view -> recyclerView_interFace.onItemClick(list.get(getBindingAdapterPosition())));

2. 更新Fragment的点击处理逻辑

在Fragment的onItemClick方法中,直接使用传递过来的对象,无需再从本地列表获取:

@Override
public void onItemClick(Product_Model product_model) {
    Intent intent = new Intent(getActivity(), Buy_Accessories.class);
    intent.putExtra("name", product_model.getOilName());
    intent.putExtra("productId", product_model.getProductId());
    intent.putExtra("image", product_model.getImageResource());
    // 注意:需在Product_Model中添加category字段,从Firebase获取数据时同步赋值,避免硬编码分类
    intent.putExtra("category", product_model.getCategory());
    startActivity(intent);
    getActivity().finish();
}

3. 优化搜索过滤逻辑

  • 修正Fragment中搜索文本变化的处理,避免重复赋值全量数据:
@Override
public boolean onQueryTextChange(String newText) {
    // 仅在全量数据未初始化时赋值
    if (adapter.allItems == null) {
        adapter.getAllItems(((Accessories_viewpager) getActivity()).allItems);
    }
    adapter.getFilter().filter(newText);
    return false;
}
  • 修复Adapter的Filter逻辑,确保清空搜索时恢复当前Fragment的原始数据:
private Filter filter = new Filter() {
    @Override
    protected FilterResults performFiltering(CharSequence charSequence) {
        List<Product_Model> filterList = new ArrayList<>();
        if (charSequence == null || charSequence.length() == 0) {
            // 清空搜索时恢复当前Fragment的原始数据
            filterList.addAll(menuModelListFilter);
        } else {
            String filterPattern = charSequence.toString().toLowerCase().trim();
            // 全局搜索遍历全量数据
            if (allItems != null) {
                for (Product_Model menu : allItems) {
                    if (menu.getOilName().toLowerCase().contains(filterPattern)) {
                        filterList.add(menu);
                    }
                }
            }
        }
        FilterResults results = new FilterResults();
        results.values = filterList;
        return results;
    }

    @Override
    protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
        list.clear();
        list.addAll((List) filterResults.values);
        notifyDataSetChanged();
    }
};

4. 完善Product_Model数据结构

在Product_Model中添加category字段及对应的getter/setter方法,同时在Firebase数据库中为每个产品添加分类属性,确保跳转时能正确传递分类信息,避免硬编码。


内容的提问来源于stack exchange,提问作者Taha Younis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 15:19:32