从数据库取数据填充自定义ListView时遇IndexOutOfBoundsException崩溃
Hey there! Let's work through this java.lang.IndexOutOfBoundsException crash you're hitting with your SQLite-powered ListView. The error message makes it clear: your adapter is trying to access index 0, but your data list has 0 items—so there's nothing to fetch at that position. Let's break down how to fix this step by step.
1. Root Cause Breakdown
This error happens for one of two core reasons:
- Your SQLite query is returning an empty list (either the database has no data, or your query is broken)
- You're attaching the adapter to the ListView before your data is loaded, or the adapter isn't properly handling an empty data set
2. Step-by-Step Fixes
First: Validate Your SQLite Query (Check DbHelper)
Let's start with your DbHelper.java—this is where your data comes from, so we need to make sure it's pulling data correctly. Here's a corrected example of a data-fetching method, with safeguards:
public class DbHelper extends SQLiteOpenHelper { // ... constructor and onCreate/onUpgrade methods ... public List<YourDataModel> getAllItems() { List<YourDataModel> itemList = new ArrayList<>(); SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery("SELECT * FROM your_table_name", null); // Only iterate if the cursor has data if (cursor.moveToFirst()) { do { // Use getColumnIndexOrThrow to catch typos in column names YourDataModel item = new YourDataModel(); item.setId(cursor.getInt(cursor.getColumnIndexOrThrow("id"))); item.setTitle(cursor.getString(cursor.getColumnIndexOrThrow("title"))); // Add other fields here itemList.add(item); } while (cursor.moveToNext()); } // Always close cursors and databases to avoid leaks cursor.close(); db.close(); return itemList; } }
Key checks for your DbHelper:
- Double-check table/column names—typos here are the #1 cause of empty results
- Use
getColumnIndexOrThrow()instead ofgetColumnIndex(): it'll throw an explicit error if a column doesn't exist, making debugging easier - Confirm your database actually has data (use tools like SQLiteStudio to inspect the .db file)
Second: Fix Your CustomAdapter's Data Handling
The crash happens on line 68 of CustomAdapter.java—that's almost certainly a line where you're calling mDataList.get(position) when mDataList is empty. Let's harden the adapter to handle empty sets:
public class CustomAdapter extends BaseAdapter { private List<YourDataModel> mDataList; private Context mContext; // Initialize with a non-null list to avoid null pointers public CustomAdapter(Context context, List<YourDataModel> dataList) { mContext = context; mDataList = dataList != null ? dataList : new ArrayList<>(); } @Override public int getCount() { // Return the actual size of the list—never a fixed number! return mDataList.size(); } @Override public Object getItem(int position) { return mDataList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // Add a safety check to avoid out-of-bounds access if (position < 0 || position >= mDataList.size()) { return convertView != null ? convertView : new View(mContext); } // Rest of your getView logic—inflating layout, binding data, etc. ViewHolder holder; if (convertView == null) { convertView = LayoutInflater.from(mContext).inflate(R.layout.your_list_item, parent, false); holder = new ViewHolder(); holder.titleTv = convertView.findViewById(R.id.title_tv); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } YourDataModel item = mDataList.get(position); holder.titleTv.setText(item.getTitle()); // Bind other views here return convertView; } // ViewHolder pattern to optimize performance private static class ViewHolder { TextView titleTv; // Add other views here } }
Third: Fix Your Data Loading Flow in the Activity/Fragment
Never attach an empty adapter to the ListView before loading data. Wait until you have the data from SQLite, then initialize and set the adapter:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = findViewById(R.id.your_list_view); DbHelper dbHelper = new DbHelper(this); // Fetch data FIRST, then set the adapter List<YourDataModel> dataList = dbHelper.getAllItems(); // Handle empty list case gracefully (no crash!) if (dataList.isEmpty()) { // Show a "no data" message instead of a blank list TextView emptyStateTv = findViewById(R.id.empty_state_tv); emptyStateTv.setVisibility(View.VISIBLE); listView.setVisibility(View.GONE); } else { CustomAdapter adapter = new CustomAdapter(this, dataList); listView.setAdapter(adapter); } }
If you're loading data asynchronously (e.g., with Kotlin Coroutines or AsyncTask), make sure you update the adapter on the main thread after data is fetched.
3. Quick Debugging Tips
- Add log statements in your DbHelper to confirm data count:
Log.d("DbHelper", "Fetched items: " + itemList.size()); - Log the data count in your adapter's constructor:
Log.d("CustomAdapter", "Received items: " + mDataList.size()); - Inspect line 68 of your adapter—if it's
mDataList.get(position), the fix above will prevent the crash when the list is empty
内容的提问来源于stack exchange,提问作者Yashna C

