从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))
);
我正在从 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))
);