NestedScrollView 是一个功能强大的 Android 支持库,它可以提供滚动功能,并且可以包含其他可滚动的视图组件。其中,最常用的就是将 RecyclerView 放在 NestedScrollView 中实现滚动效果。然而,这种做法有时会导致 RecyclerView 中的元素全部加载,从而导致内存膨胀的问题。
在我们的日常开发中,经常会遇到需要在一个界面中同时显示多个列表的情况。为了方便用户查看,我们通常会使用 NestedScrollView 包裹 RecyclerView,以实现整体的滚动效果。然而,当 RecyclerView 中的元素较多时,使用这种方式会导致所有的元素一次性加载到内存中,从而导致内存占用过大,界面卡顿的问题。那么,如何解决这个问题呢?下面我们将通过一个案例来详细介绍。问题分析:假设我们有一个需求,要在一个界面中同时展示两个列表:列表 A 和列表 B。为了方便用户查看,我们将这两个列表放在一个 NestedScrollView 中实现滚动效果。我们使用 RecyclerView 分别展示列表 A 和列表 B 的数据,并且通过 Adapter 将数据传递给 RecyclerView。问题重现:为了演示这个问题,我们创建一个简单的示例项目。首先,在布局文件中添加一个 NestedScrollView,然后在其中分别添加两个 RecyclerView。接着,我们分别创建两个 Adapter,并通过数据源将数据传递给它们。最后,将 Adapter 设置给 RecyclerView,并将 RecyclerView 添加到布局文件中。案例代码如下所示:xml接下来,我们在代码中实现这两个 RecyclerView 的逻辑。首先,我们创建一个数据源,用于存储列表 A 和列表 B 的数据。然后,我们分别创建两个 Adapter,并将数据源传递给它们。最后,将 Adapter 设置给 RecyclerView,并将 RecyclerView 添加到布局文件中。android:layout_width="match_parent" android:layout_height="match_parent"> android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> android:id="@+id/recyclerViewA" android:layout_width="match_parent" android:layout_height="wrap_content" /> android:id="@+id/recyclerViewB" android:layout_width="match_parent" android:layout_height="wrap_content" />
java// 创建数据源List解决方案:为了解决 RecyclerView 中的元素全部加载导致内存膨胀的问题,我们可以使用以下两种方式之一:1. 使用嵌套的 RecyclerView:将 RecyclerView A 和 RecyclerView B 放在一个 LinearLayout 中,并将 LinearLayout 设置给 RecyclerView 的一个 item。这样,当 RecyclerView 在屏幕上显示时,只会加载当前可见区域的 item,从而减少了内存的占用。2. 使用分页加载:将 RecyclerView 中的数据进行分页,每次只加载当前页的数据。当用户滚动到底部时,再加载下一页的数据。这样,不仅可以减少内存的占用,还可以提高用户体验。使用嵌套的 RecyclerView:首先,我们需要修改布局文件,将 LinearLayout 替换为 RecyclerView,并设置 RecyclerView 的布局管理器为 LinearLayoutManager。dataA = new ArrayList<>();List dataB = new ArrayList<>();// 添加数据for (int i = 0; i < 100; i++) { dataA.add("Item A " + i); dataB.add("Item B " + i);}// 创建 AdapterRecyclerView.Adapter adapterA = new RecyclerViewAdapter(dataA);RecyclerView.Adapter adapterB = new RecyclerViewAdapter(dataB);// 设置 AdapterRecyclerView recyclerViewA = findViewById(R.id.recyclerViewA);recyclerViewA.setLayoutManager(new LinearLayoutManager(this));recyclerViewA.setAdapter(adapterA);RecyclerView recyclerViewB = findViewById(R.id.recyclerViewB);recyclerViewB.setLayoutManager(new LinearLayoutManager(this));recyclerViewB.setAdapter(adapterB);
xml接下来,我们需要修改代码,将数据源中的数据进行分页,并将每一页的数据传递给 Adapter。android:layout_width="match_parent" android:layout_height="match_parent"> android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" />
java// 创建数据源List最后,我们需要创建一个新的 Adapter,用于加载每一页的数据。> data = new ArrayList<>();// 添加数据for (int i = 0; i < 10; i++) { List
pageData = new ArrayList<>(); for (int j = 0; j < 10; j++) { pageData.add("Item " + (i * 10 + j)); } data.add(pageData);}// 创建 AdapterRecyclerView.Adapter adapter = new NestedRecyclerViewAdapter(data);// 设置 AdapterRecyclerView recyclerView = findViewById(R.id.recyclerView);recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setAdapter(adapter);
javapublic class NestedRecyclerViewAdapter extends RecyclerView.Adapter分页加载:首先,我们需要对数据源进行分页处理。可以通过添加分页标识字段,将数据分为多个页,并根据页码加载相应的数据。{ private List > mData; public NestedRecyclerViewAdapter(List
> data) { mData = data; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_nested_recyclerview, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { List
pageData = mData.get(position); RecyclerView.Adapter adapter = new RecyclerViewAdapter(pageData); holder.recyclerView.setLayoutManager(new LinearLayoutManager(holder.itemView.getContext())); holder.recyclerView.setAdapter(adapter); } @Override public int getItemCount() { return mData.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { RecyclerView recyclerView; public ViewHolder(View itemView) { super(itemView); recyclerView = itemView.findViewById(R.id.recyclerView); } }}
javapublic class DataItem { private String content; private int page; public DataItem(String content, int page) { this.content = content; this.page = page; } public String getContent() { return content; } public int getPage() { return page; }}// 创建数据源List接着,我们需要修改 Adapter 的逻辑,在 onBindViewHolder 方法中根据页码加载相应的数据。data = new ArrayList<>();// 添加数据for (int i = 0; i < 100; i++) { int page = i / 10 + 1; data.add(new DataItem("Item " + i, page));}
java@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) { List最后,我们需要为 RecyclerView 添加滚动监听器,当用户滚动到底部时,加载下一页的数据。pageData = new ArrayList<>(); for (DataItem item : mData) { if (item.getPage() == position + 1) { pageData.add(item.getContent()); } } RecyclerView.Adapter adapter = new RecyclerViewAdapter(pageData); holder.recyclerView.setLayoutManager(new LinearLayoutManager(holder.itemView.getContext())); holder.recyclerView.setAdapter(adapter);}
javarecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); int totalItemCount = layoutManager.getItemCount(); int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); if (lastVisibleItemPosition == totalItemCount - 1) { // 加载下一页的数据 int nextPage = mData.get(totalItemCount - 1).getPage() + 1; for (int i = 0; i < 10; i++) { int index = (nextPage - 1) * 10 + i; mData.add(new DataItem("Item " + index, nextPage)); } adapter.notifyDataSetChanged(); } }});通过以上两种方式,我们可以有效地解决 NestedScrollView 内的 RecyclerView 导致内存膨胀的问题。使用嵌套的 RecyclerView 或分页加载,可以减少内存的占用,提高应用的性能和用户体验。