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

使用ZXing扫码获取API响应时RecyclerView新增数据异常

RecyclerView扫码加载商品数据异常修复

问题场景

通过ZXing扫码器获取二维码内容后发起结算API请求,尝试将接口返回的商品数据逐次追加到RecyclerView列表中展示,但现有代码数据插入、刷新逻辑异常,无法实现预期的逐次新增效果。涉及的代码、接口返回信息如下:

适配器实现代码

public class checkoutAdapter extends RecyclerView.Adapter<checkoutAdapter.NewViewHolder>{

    public ArrayList<DataCheckout> arrayList;

    public checkoutAdapter(ArrayList<DataCheckout> arrayList) {
        this.arrayList = arrayList;
    }

    @NonNull
    @Override
    public NewViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.checkout_layout, parent, false);
        return new NewViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull NewViewHolder holder, int position) {
        holder.code.setText(arrayList.get(position).getItem_code());
        holder.item.setText(arrayList.get(position).getItem_name());
        holder.price.setText(arrayList.get(position).getSelling_price());
        holder.quantity.setText(arrayList.get(position).getRefquantity());
    }

    public void onRefreshAdapter(ArrayList<DataCheckout> yourList) {
        arrayList = yourList;
        notifyDataSetChanged();
    }

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


    public class NewViewHolder extends RecyclerView.ViewHolder{

        TextView code, item, price, quantity;

        public NewViewHolder(@NonNull View itemView) {
            super(itemView);
            code = itemView.findViewById(R.id.txtCode);
            item = itemView.findViewById(R.id.txtItem);
            price = itemView.findViewById(R.id.txtPrice);
            quantity = itemView.findViewById(R.id.txtQuantity);
        }
    }
}

Activity实现代码

public class CheckoutActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private checkoutAdapter adapter;
    DentalApi dentalApi;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_checkout);

        recyclerView = findViewById(R.id.rcCheckout);

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
        recyclerView.setLayoutManager(layoutManager);
        Button btScan = findViewById(R.id.btnScan);


        btScan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                IntentIntegrator intentIntegrator = new IntentIntegrator(CheckoutActivity.this);
                intentIntegrator.setPrompt("Scan a QR Code");
                intentIntegrator.setOrientationLocked(true);
                intentIntegrator.initiateScan();
                intentIntegrator.setCameraId(0);
            }
        });

    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        TextView txtView = findViewById(R.id.txtInfo);
        IntentResult intentResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
        if (intentResult != null) {
            if (intentResult.getContents() == null) {
                Toast.makeText(getBaseContext(), "Cancelled", Toast.LENGTH_SHORT).show();
            } else {
                dentalApi = ApiClient.getRetrofit().create(DentalApi.class);
                dentalApi.checkout("Bearer 13|nIl6vhT8z0Yt52vLKtCUnJTdXxE1fA3B97Bv7wvq", intentResult.getContents()).enqueue(new Callback<CheckoutResponse>() {
                    @Override
                    public void onResponse(Call<CheckoutResponse> call, Response<CheckoutResponse> response) {
                        CheckoutResponse chechoutResponse = null;
                        if (response.isSuccessful()){
                            chechoutResponse = response.body();
                            if (chechoutResponse.getStatus().equals(1));
                            List<DataCheckout> datalist = response.body().getData();
                            for (int i = 0; i < datalist.size(); i++) {
                                adapter = new checkoutAdapter((ArrayList<DataCheckout>) datalist);
                                recyclerView.setAdapter(adapter);
                                adapter.notifyItemInserted(datalist.size() - 1);
                            }
                        }
                    }
                    @Override
                    public void onFailure(Call<CheckoutResponse> call, Throwable t) {

                    }
                });
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }
}

API响应参考

API响应截图

问题根因

现有代码存在5个核心逻辑错误,直接导致列表新增效果失效:

  • 适配器重复实例化:接口返回后在for循环内反复new checkoutAdapter、重复调用recyclerView.setAdapter(),每次都会用当次返回的新列表覆盖原有列表,历史扫码的商品数据会全部丢失,无法实现累加展示
  • 适配器初始化时机错误:Activity启动时从未初始化adapter实例,首次回调时直接操作未实例化的对象存在极高的空指针崩溃风险
  • 刷新逻辑无效:在新创建的适配器上调用notifyItemInserted没有实际意义,此时适配器绑定的是仅包含当次商品的全新列表,不存在“插入新条目”的场景
  • 语法错误:if (chechoutResponse.getStatus().equals(1)); 末尾多写了分号,导致状态判断逻辑完全失效,哪怕接口返回错误状态码也会继续执行列表加载逻辑
  • 异常处理缺失:接口请求失败的回调为空,请求出错时没有任何提示,问题无法快速定位
    *额外问题:扫码配置顺序错误,initiateScan()调用后才设置摄像头ID,该参数不会生效。

修复步骤

1. 改造适配器,新增数据追加方法

在原有适配器中新增单条/批量追加数据的方法,不需要每次替换整个列表:

// 新增批量追加数据方法
public void addAllItems(List<DataCheckout> items) {
    int insertStartPos = arrayList.size();
    arrayList.addAll(items);
    notifyItemRangeInserted(insertStartPos, items.size());
}

// 可选:新增单条数据追加方法,适配单商品扫码场景
public void addSingleItem(DataCheckout item) {
    arrayList.add(item);
    notifyItemInserted(arrayList.size() - 1);
}

// 原有全量刷新方法可保留,适配全量重置列表的场景
public void onRefreshAdapter(ArrayList<DataCheckout> yourList) {
    arrayList = yourList;
    notifyDataSetChanged();
}

2. 在onCreate中初始化适配器,仅绑定一次RecyclerView

在Activity创建时就初始化空数据列表和适配器,一次性给RecyclerView设置适配器,后续不再重复实例化、重复绑定,同时修正扫码参数的配置顺序:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_checkout);

    recyclerView = findViewById(R.id.rcCheckout);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(layoutManager);
    
    // 初始化空列表和适配器,仅设置一次
    ArrayList<DataCheckout> dataList = new ArrayList<>();
    adapter = new checkoutAdapter(dataList);
    recyclerView.setAdapter(adapter);

    Button btScan = findViewById(R.id.btnScan);
    btScan.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            IntentIntegrator intentIntegrator = new IntentIntegrator(CheckoutActivity.this);
            intentIntegrator.setPrompt("Scan a QR Code");
            intentIntegrator.setOrientationLocked(true);
            intentIntegrator.setCameraId(0);
            // 所有配置完成后再启动扫码
            intentIntegrator.initiateScan();
        }
    });
}

3. 改造接口回调逻辑,直接追加数据

拿到接口返回的有效数据后,直接调用适配器的追加方法新增条目,同时修复语法错误、补全异常提示:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    IntentResult intentResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
    if (intentResult != null) {
        if (intentResult.getContents() == null) {
            Toast.makeText(getBaseContext(), "Cancelled", Toast.LENGTH_SHORT).show();
        } else {
            dentalApi = ApiClient.getRetrofit().create(DentalApi.class);
            dentalApi.checkout("Bearer 13|nIl6vhT8z0Yt52vLKtCUnJTdXxE1fA3B97Bv7wvq", intentResult.getContents()).enqueue(new Callback<CheckoutResponse>() {
                @Override
                public void onResponse(Call<CheckoutResponse> call, Response<CheckoutResponse> response) {
                    if (response.isSuccessful()){
                        CheckoutResponse checkoutResponse = response.body();
                        // 修复多余分号问题,增加空判断避免空指针
                        if (checkoutResponse != null && checkoutResponse.getStatus() == 1) {
                            List<DataCheckout> newDataList = checkoutResponse.getData();
                            if (newDataList != null && newDataList.size() > 0) {
                                // 直接追加数据到现有列表,不需要重新创建适配器
                                adapter.addAllItems(newDataList);
                                // 可选:自动滚动到最新添加的条目位置
                                recyclerView.scrollToPosition(adapter.getItemCount() - 1);
                            } else {
                                Toast.makeText(CheckoutActivity.this, "未查询到对应商品信息", Toast.LENGTH_SHORT).show();
                            }
                        } else {
                            Toast.makeText(CheckoutActivity.this, "商品查询失败,请重试", Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        Toast.makeText(CheckoutActivity.this, "请求异常,请检查网络", Toast.LENGTH_SHORT).show();
                    }
                }
                @Override
                public void onFailure(Call<CheckoutResponse> call, Throwable t) {
                    Toast.makeText(CheckoutActivity.this, "网络错误:" + t.getMessage(), Toast.LENGTH_SHORT).show();
                }
            });
        }
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

编码规范提示:Java类名建议遵循大驼峰命名规则,将checkoutAdapter重命名为CheckoutAdapter,可减少后续维护、编译阶段的歧义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:18:10