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

如何在RecyclerView滚动时从SQLite分批加载数据优化性能

实现RecyclerView分页加载SQLite数据

要解决大量数据加载缓慢的问题,最直接的方案是分页加载——每次仅加载当前屏幕可容纳的若干条数据,当用户滚动到列表底部时,再加载下一页数据。以下是具体实现步骤:

1. 修改DatabaseHelper,支持分页查询

给数据库查询方法添加分页参数,利用SQLite的LIMIT和OFFSET关键字实现分段查询,同时新增方法获取总数据量,用于判断是否还有更多数据可加载。

public class DatabaseHelper extends SQLiteOpenHelper {
    // ... 其他已有代码

    // 分页获取数据:page为当前页码(从1开始),pageSize为每页条数
    public ArrayList<AuthorInfo> getAuthorInfo(int page, int pageSize) {
        ArrayList<AuthorInfo> arraylist = new ArrayList<>();
        SQLiteDatabase dB = this.getReadableDatabase();
        // 计算偏移量:OFFSET = (页码-1)*每页条数
        String query = "SELECT * FROM table LIMIT ? OFFSET ?";
        Cursor c = dB.rawQuery(query, new String[]{String.valueOf(pageSize), String.valueOf((page - 1) * pageSize)});
        
        if (c.moveToFirst()) {
            do {
                AuthorInfo authorInfo = new AuthorInfo();
                // 注意:原代码中getName和getSubject都取了c.getString(0),应为字段索引错误,这里修正为set方法并对应正确列索引
                authorInfo.setName(c.getString(0));
                authorInfo.setSubject(c.getString(1));
                arraylist.add(authorInfo);
            } while (c.moveToNext());
        }
        c.close();
        dB.close();
        return arraylist;
    }

    // 获取总数据条数,判断是否还有下一页
    public int getTotalAuthorCount() {
        SQLiteDatabase dB = this.getReadableDatabase();
        Cursor c = dB.rawQuery("SELECT COUNT(*) FROM table", null);
        int count = 0;
        if (c.moveToFirst()) {
            count = c.getInt(0);
        }
        c.close();
        dB.close();
        return count;
    }
}

2. 改造RecyclerView适配器,支持批量添加数据

让适配器支持向现有列表追加新数据,而非每次替换整个列表,避免重复刷新,提升性能。

public class RecyclerviewAdapter extends RecyclerView.Adapter<RecyclerviewAdapter.ViewHolder> {
    private Context context;
    private ArrayList<AuthorInfo> authorList;

    public RecyclerviewAdapter(Context context, ArrayList<AuthorInfo> authorList) {
        this.context = context;
        this.authorList = authorList;
    }

    // 批量添加数据的方法
    public void addAll(ArrayList<AuthorInfo> newAuthors) {
        int startPosition = authorList.size();
        authorList.addAll(newAuthors);
        // 仅通知新增项的位置,而非刷新整个列表
        notifyItemRangeInserted(startPosition, newAuthors.size());
    }

    // ... 其他已有方法(ViewHolder、onCreateViewHolder、onBindViewHolder等)
}

3. 在MainActivity中实现分页加载逻辑

维护当前页码、每页条数,添加滚动监听判断是否到达底部,异步加载下一页数据(Java版本用AsyncTask实现):

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerviewer;
    private RecyclerviewAdapter adapter;
    private DatabaseHelper database;
    private ArrayList<AuthorInfo> authorInfoList;
    private int currentPage = 1;
    private final int PAGE_SIZE = 20; // 每页加载20条,可按需调整
    private boolean isLoading = false; // 防止重复触发加载
    private int totalCount; // 总数据条数

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

        recyclerviewer = findViewById(R.id.recyclerview);
        recyclerviewer.setLayoutManager(new LinearLayoutManager(this));

        database = new DatabaseHelper(getApplicationContext());
        totalCount = database.getTotalAuthorCount();
        authorInfoList = new ArrayList<>();
        adapter = new RecyclerviewAdapter(getApplicationContext(), authorInfoList);
        recyclerviewer.setAdapter(adapter);

        // 加载第一页数据
        loadNextPage();

        // 添加滚动监听,判断是否触发下一页加载
        recyclerviewer.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();
                assert layoutManager != null;
                // 滚动到最后一条、未在加载中、还有剩余数据时,加载下一页
                if (!isLoading && layoutManager.findLastVisibleItemPosition() == authorInfoList.size() - 1
                        && authorInfoList.size() < totalCount) {
                    loadNextPage();
                }
            }
        });
    }

    // 异步加载下一页数据
    private void loadNextPage() {
        isLoading = true;
        new AsyncTask<Void, Void, ArrayList<AuthorInfo>>() {
            @Override
            protected ArrayList<AuthorInfo> doInBackground(Void... voids) {
                return database.getAuthorInfo(currentPage, PAGE_SIZE);
            }

            @Override
            protected void onPostExecute(ArrayList<AuthorInfo> authors) {
                super.onPostExecute(authors);
                if (authors != null && !authors.isEmpty()) {
                    adapter.addAll(authors);
                    currentPage++;
                }
                isLoading = false;
            }
        }.execute();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (database != null) {
            database.close();
        }
    }
}

注意事项

  • 原代码中authorInfo.getName(c.getString(0))和authorInfo.getSubject(c.getString(0))存在错误,应调用setName/setSubject方法,并对应数据库中实际的列索引。
  • 每页条数PAGE_SIZE可根据列表项高度调整,通常20-30条较为合适。
  • 必须异步加载数据,禁止在主线程操作数据库,避免UI卡顿或ANR。
  • 可给列表底部添加"加载中"Footer,提升用户体验,加载完成后隐藏即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 18:56:22