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

如何用CursorAdapter从SQLite在ListView显示图文并实现搜索?求StaleDataException解决方案

Hey there, let's tackle this StaleDataException issue you're facing with your CursorAdapter! This error pops up when your code tries to access a Cursor that's already been closed or deactivated—super common when working with dynamic data like search results. Let's break down the problem and fix it step by step.

Why This Happens

Looking at your code snippet, the main red flag is that you're manually storing a reference to the Cursor (private Cursor c;). The built-in CursorAdapter already manages its own Cursor lifecycle, and keeping a separate reference can lead to desync: when you update the Cursor (like for search), your stored c might still point to the old, closed Cursor while the adapter has moved to a new one.

Step-by-Step Fixes

1. Ditch the Manual Cursor Reference

Remove the private Cursor c; field and stop assigning it in the constructor. Instead, always use the adapter's getCursor() method to access the active, up-to-date Cursor whenever you need it.

When you perform a search and get a new result Cursor, never close the old Cursor manually or replace it directly. Use swapCursor(newCursor)—this method safely replaces the adapter's Cursor, handles closing the old one (if needed), and keeps the adapter in sync with valid data.

3. Safe Data Reading in getView

In your getView method, always fetch the active Cursor, verify it's valid, and read data directly from it (don't store data like byte[] image as a global variable, since it might reference stale Cursor data).

Modified ImageCursorAdapter Example

public class ImageCursorAdapter extends CursorAdapter {
    private Context context;

    public ImageCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
        super(context, layout, c, from, to);
        this.context = context;
        // No more storing Cursor reference here!
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Reuse the convertView or inflate a new one
        View view = convertView;
        if (view == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.your_list_item_layout, parent, false);
        }

        // Get the active Cursor from the adapter
        Cursor cursor = getCursor();
        if (cursor != null && cursor.moveToPosition(position)) {
            // Read text (replace "name" with your actual column name)
            String itemName = cursor.getString(cursor.getColumnIndexOrThrow("name"));
            // Read image bytes (replace "image" with your actual column name)
            byte[] imageBytes = cursor.getBlob(cursor.getColumnIndexOrThrow("image"));

            // Update TextView
            TextView nameTextView = view.findViewById(R.id.item_name);
            nameTextView.setText(itemName);

            // Update ImageView
            ImageView itemImageView = view.findViewById(R.id.item_image);
            if (imageBytes != null && imageBytes.length > 0) {
                Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
                itemImageView.setImageBitmap(bitmap);
            } else {
                // Set a default image if no data exists
                itemImageView.setImageResource(R.drawable.default_image);
            }
        }
        return view;
    }
}

How to Handle Search Updates

In your Activity/Fragment where you implement the search functionality, use this pattern to update the adapter:

// Example search method
private void runSearch(String searchQuery) {
    // Get new Cursor from your SQLite helper with search results
    Cursor searchResultsCursor = yourDbHelper.getItemsByName(searchQuery);
    // Swap the adapter's Cursor to the new one
    yourImageCursorAdapter.swapCursor(searchResultsCursor);
}

Extra Lifecycle Tips

  • When your Activity/Fragment is destroyed, call yourImageCursorAdapter.changeCursor(null) to properly close the Cursor and avoid memory leaks.
  • Avoid using changeCursor() for search updates unless you explicitly want to close the old Cursor immediately—swapCursor() is safer for dynamic data changes.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:25:49