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

使用Retrofit获取数据时嵌套RecyclerView为空的问题排查

问题排查与优化方案

核心问题分析

你的代码存在几个关键问题导致界面为空:

1. 异步加载未通知适配器更新

buildItemList() 和 buildSubItemList() 中,Retrofit的enqueue是异步调用,你在发起请求后立刻返回空列表,而当网络请求完成、数据添加到集合后,没有通知RecyclerView适配器数据已变更,导致界面无法刷新。

2. API接口设计不合理

两个接口getItem()和getSubItem()都请求同一个/job端点,不符合嵌套数据逻辑。正常来说,父级Item应包含对应的子级SubItem列表,API应直接返回包含子项的Item集合,而非分开请求。

3. 数据处理逻辑混乱

  • 在getItem()的onResponse中,先添加接口返回的真实数据,再循环添加虚拟Item对象,导致数据重复或混乱。
  • 调用buildSubItemList()创建子项列表时,同样是异步请求,返回的列表为空(请求未完成)。

4. Model类序列化可能不匹配

Item类的subItemList字段未添加@SerializedName注解,如果API返回的字段名不是subItemList(比如sub_items),Gson无法正确解析子项列表,导致父项子列表为空。


修复与优化步骤

1. 修正API接口与数据结构

假设API返回的每个job包含客户信息和对应子任务列表,修改API接口为单次请求:

public interface API {
    @GET("job")
    Call<ArrayList<Item>> getItemList();
}

同时确保Item类的子列表字段与API返回字段匹配:

public class Item {
    @SerializedName("customer_name")
    private String customer_name;

    @SerializedName("sub_items") // 根据实际API字段名修改
    private List<SubItem> subItemList;

    // 构造方法、getter、setter...
}

2. 重构数据加载逻辑,通知适配器更新

在MainActivity中直接发起网络请求,请求完成后更新数据并通知适配器:

public class MainActivity extends AppCompatActivity {
    private ArrayList<Item> itemList = new ArrayList<>();
    private ItemAdapter itemAdapter;

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

        RecyclerView rvItem = findViewById(R.id.rv_item);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        itemAdapter = new ItemAdapter(itemList);
        rvItem.setAdapter(itemAdapter);
        rvItem.setLayoutManager(layoutManager);

        loadData();
    }

    private void loadData() {
        Call<ArrayList<Item>> call = RetrofitClient.getInstance().getAPI().getItemList();
        call.enqueue(new Callback<ArrayList<Item>>() {
            @Override
            public void onResponse(Call<ArrayList<Item>> call, Response<ArrayList<Item>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    itemList.clear();
                    itemList.addAll(response.body());
                    itemAdapter.notifyDataSetChanged();
                }
            }

            @Override
            public void onFailure(Call<ArrayList<Item>> call, Throwable t) {
                Log.e("MainActivity", "加载失败", t);
                Toast.makeText(getApplicationContext(), "加载失败:" + t.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }
}

3. 优化嵌套RecyclerView性能

避免在onBindViewHolder中重复创建布局管理器和适配器:

public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemViewHolder> {
    private final RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
    private final List<Item> itemList;

    public ItemAdapter(List<Item> itemList) {
        this.itemList = itemList;
    }

    @NonNull
    @Override
    public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_item, viewGroup, false);
        return new ItemViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ItemViewHolder itemViewHolder, int i) {
        Item item = itemList.get(i);
        itemViewHolder.customer_name.setText(item.getCustomer_name());

        if (itemViewHolder.rvSubItem.getLayoutManager() == null) {
            LinearLayoutManager layoutManager = new LinearLayoutManager(
                    itemViewHolder.rvSubItem.getContext(),
                    LinearLayoutManager.VERTICAL,
                    false
            );
            layoutManager.setInitialPrefetchItemCount(item.getSubItemList().size());
            itemViewHolder.rvSubItem.setLayoutManager(layoutManager);
            itemViewHolder.rvSubItem.setRecycledViewPool(viewPool);
        }

        SubItemAdapter subItemAdapter = (SubItemAdapter) itemViewHolder.rvSubItem.getAdapter();
        if (subItemAdapter == null) {
            subItemAdapter = new SubItemAdapter(item.getSubItemList());
            itemViewHolder.rvSubItem.setAdapter(subItemAdapter);
        } else {
            subItemAdapter.updateData(item.getSubItemList());
        }
    }

    // ...其他代码

    class ItemViewHolder extends RecyclerView.ViewHolder {
        TextView customer_name;
        RecyclerView rvSubItem;

        ItemViewHolder(View itemView) {
            super(itemView);
            customer_name = itemView.findViewById(R.id.todocustomer_name);
            rvSubItem = itemView.findViewById(R.id.rv_sub_item);
        }
    }
}

在SubItemAdapter中添加数据更新方法:

public class SubItemAdapter extends RecyclerView.Adapter<SubItemAdapter.SubItemViewHolder> {
    private List<SubItem> subItemList;

    public SubItemAdapter(List<SubItem> subItemList) {
        this.subItemList = subItemList;
    }

    public void updateData(List<SubItem> newList) {
        this.subItemList.clear();
        this.subItemList.addAll(newList);
        notifyDataSetChanged();
    }

    // ...其他代码
}

4. 完善错误处理

添加日志打印便于排查网络问题:

@Override
public void onFailure(Call<ArrayList<Item>> call, Throwable t) {
    Log.e("MainActivity", "网络请求失败", t);
    Toast.makeText(getApplicationContext(), "加载失败:" + t.getMessage(), Toast.LENGTH_LONG).show();
}

额外优化建议

  • 使用ViewModel和LiveData管理数据,避免屏幕旋转时数据丢失或重复请求。
  • 添加加载状态(如ProgressBar),提升用户体验。
  • 对RecyclerView子项使用DiffUtil进行局部更新,提升性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 09:42:05