从sqlite数据库在recyclerview中设置数据时出现IndexOutOfBound异常

IndexOutOfBound Exception while setting the data in recyclerview from sqlite database

我正在从 sqlite 中获取数据并将其填充到 recyclerview 中,但是在填充数据时我在 logcat 中遇到了 IndexOutOfBoundException。 谁能告诉我为什么会出现此异常?

数据库助手class代码:

public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "history.db";
public  static final String TABLE_NAME = "history_table";
public static  final String COL_1 = "ID";
public static  final String COL_2 = "URL";
public  static final String COL_3 = "TITLE";
public DatabaseHelper(@Nullable Context context) {
    super(context, DATABASE_NAME, null, 1);
    SQLiteDatabase db = this.getWritableDatabase();
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL("CREATE TABLE "+ TABLE_NAME+"(ID INTEGER PRIMARY KEY AUTOINCREMENT, URL TEXT, TITLE TEXT)");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME);
    onCreate(db);
}
public  boolean insertData(String url, String title){
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues contentValues = new ContentValues();
    contentValues.put(COL_2, url);
    contentValues.put(COL_3, title);
    long result = db.insert(TABLE_NAME,null,contentValues);
    if(result == -1) {
        return false;
    }
    else{
        return true;
    }

}
public  boolean updateData(String id, String url, String title) {
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues contentValue= new ContentValues();
    contentValue.put(COL_1, id);
    contentValue.put(COL_2, url);
    contentValue.put(COL_3, title);
    db.update(TABLE_NAME, contentValue, "ID= ?",new String[]{id} );
    return true;
}
public Cursor getalldata() {
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor res = db.rawQuery("select * from "+ TABLE_NAME, null);
    return res;
}
public Cursor getuniquedata(String id){
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor res = db.rawQuery("select * from "+ TABLE_NAME+" where " +COL_2+" = ?", new String []{id});
    return res;
}
public void deletedata(String id){
    SQLiteDatabase db = this.getWritableDatabase();
    db.delete(TABLE_NAME, COL_2+ "= ?", new String []{id});

} }

我在模型中填充数据并设置适配器时的代码:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    view =  inflater.inflate(R.layout.fragment_history, container, false);
    button = (Button) view.findViewById(R.id.button1);
    recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview8);
    historyModels = new ArrayList<>();
    LinearLayoutManager mainlayout= new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL,false);
    recyclerView.setLayoutManager(mainlayout);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    mydb = new DatabaseHelper(getContext());
    Cursor res = mydb.getalldata();
    res.moveToFirst();
    if(res!=null) {
            while (res.moveToNext()) ;
            {
                HistoryModel historyModel = new HistoryModel(res.getString(1), res.getString(2));  //this line is giving error
                historyModels.add(historyModel);
            }
        mydb.close();
        historyRecyclerAdapter = new HistoryRecyclerAdapter(historyModels, getContext());
        recyclerView.setAdapter(historyRecyclerAdapter);
    }
    return view;
}

回收器适配器class:

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
    mydb = new DatabaseHelper(context);
    final HistoryModel historyModel = (HistoryModel) historyModels.get(position);
    Picasso.get().load("https://img.youtube.com/vi/"+historyModel.getDetailimg()+"/mqdefault.jpg").into(holder.imageView);
    holder.textView.setText(historyModel.getDetailtext());
    holder.delbutton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mydb.deletedata(historyModels.get(position).getDetailimg());
            historyModels.remove(position);
            notifyItemRemoved(position);
            notifyItemRangeChanged(position, historyModels.size());
            Toast.makeText(context, "Video Removed Successfully", Toast.LENGTH_LONG).show();

        }
    });
}

LogcatError:

android.database.CursorIndexOutOfBoundsException: Index 8 requested, with a size of 8
    at android.database.AbstractCursor.checkPosition(AbstractCursor.java:460)
    at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
    at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
    at com.example.haryanvigaane.Fragment.HistoryFragment.onCreateView(HistoryFragment.java:77)
    at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
    at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
    at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
    at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
    at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
    at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
    at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
    at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
    at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)

首先是这一行:

res.moveToFirst();

Cursor 的索引移动到第一行 然后你开始一个空循环:

while (res.moveToNext());

因为末尾的分号,即使您将其删除,您创建的列表也会错过第一行。
在这个空循环之后,它只推进 Cursor 的索引,并最终在 Cursor 的最后一行 之后将其设置为 ,在下面的代码块中花括号(不是 while 的一部分)您尝试检索 2 列的值,这是抛出错误的地方,因为那里没有行 Cursor 的索引是。
将代码更改为:

Cursor res = mydb.getalldata();
while (res.moveToNext()) {
    HistoryModel historyModel = new HistoryModel(res.getString(1), res.getString(2));     
    historyModels.add(historyModel);
}
res.close();
mydb.close();
historyRecyclerAdapter = new HistoryRecyclerAdapter(historyModels, getContext());
recyclerView.setAdapter(historyRecyclerAdapter);

请注意,使用 getColumnIndex() 而不是显式设置列的索引是一种很好的做法,因此我建议这样做:

HistoryModel historyModel = new HistoryModel(
    res.getString(res.getColumnIndex(DatabaseHelper.URL)), 
    res.getString(res.getColumnIndex(DatabaseHelper.TITLE))
);