Search code examples
androidandroid-viewpagerandroid-sqlite

Error-CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0


MY PROBLEM:

In my project I have a sqlite database. I tried testing these same classes(Database Handler class and the helper class-Hitlist.java) in another project doing simple operations like adding to database, getting count, getting list of all rows in database and it worked just fine. But in this project with viewpager where each page extracts data from database, this error is showing up when my view pager adapter asks for a row from database. I have seen many questions on StackOverflow with similar titles but none of them solves my problem.

The logcat:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rohan.hitlistofarya/com.rohan.hitlistofarya.MainActivity}: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
                                                                             at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2456)
                                                                             at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2539)
                                                                             at android.app.ActivityThread.access$900(ActivityThread.java:159)
                                                                             at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1384)
                                                                             at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                             at android.os.Looper.loop(Looper.java:152)
                                                                             at android.app.ActivityThread.main(ActivityThread.java:5507)
                                                                             at java.lang.reflect.Method.invoke(Native Method)
                                                                             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                                          Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
                                                                             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.rohan.hitlistofarya.DBHandler.getPerson(DBHandler.java:102)
                                                                             at com.rohan.hitlistofarya.VpagerAdapter.getPageTitle(VpagerAdapter.java:40)
                                                                             at android.support.design.widget.TabLayout.populateFromPagerAdapter(TabLayout.java:903)
                                                                             at android.support.design.widget.TabLayout.setPagerAdapter(TabLayout.java:894)
                                                                             at android.support.design.widget.TabLayout.setupWithViewPager(TabLayout.java:807)
                                                                             at android.support.design.widget.TabLayout.setupWithViewPager(TabLayout.java:768)
                                                                             at android.support.design.widget.TabLayout.setupWithViewPager(TabLayout.java:746)
                                                                             at com.rohan.hitlistofarya.MainFragment.onCreateView(MainFragment.java:48)
                                                                             at android.support.v4.app.Fragment.performCreateView(Fragment.java:2080)
                                                                             at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1108)
                                                                             at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1290)
                                                                             at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801)
                                                                             at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1677)
                                                                             at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:388)
                                                                             at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:604)
                                                                             at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
                                                                             at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1277)
                                                                             at android.app.Activity.performStart(Activity.java:6321)
                                                                             at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2419)
                                                                             at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2539) 
                                                                             at android.app.ActivityThread.access$900(ActivityThread.java:159) 
                                                                             at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1384) 
                                                                             at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                             at android.os.Looper.loop(Looper.java:152) 
                                                                             at android.app.ActivityThread.main(ActivityThread.java:5507) 
                                                                             at java.lang.reflect.Method.invoke(Native Method) 
                                                                             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

The DBHandler class:

public class DBHandler extends SQLiteOpenHelper {

    private static DBHandler sInstance;

    private static final int DATABASE_VERSION = 1;


    private static final String DATABASE_NAME = "hitlist";


    private static final String TABLE_NAME = "hitlistOfArya";


    private static final String COLUMN_ID = "id";
    private static final String COLUMN_NAME = "name";
    private static final String COLUMN_REASON = "reason";
    private static final String COLUMN_STATUS="dead";
    private static final String COLUMN_FATE="fate";
    private static final String COLUMN_HOUSE="allegiance";
    private static final String COLUMN_EXTRA="extra";
    private static final String COLUMN_IMG="image";

    private DBHandler(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    public static synchronized DBHandler getInstance(Context context) {

        if (sInstance == null) {
            sInstance = new DBHandler(context.getApplicationContext());
        }
        return sInstance;
    }


    @Override
    public void onCreate(SQLiteDatabase db) {
        String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_NAME + "("
                + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + COLUMN_NAME + " TEXT,"
                + COLUMN_REASON + " TEXT,"
                + COLUMN_STATUS + " INTEGER,"
                + COLUMN_FATE + " TEXT,"
                + COLUMN_HOUSE + " TEXT,"
                + COLUMN_EXTRA + " TEXT,"
                + COLUMN_IMG + " TEXT" + ")";
        db.execSQL(CREATE_CONTACTS_TABLE);
    }


    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);

// Create tables again
        onCreate(db);
    }


    public void addPerson(Hitlist person) {
        SQLiteDatabase db = this.getWritableDatabase();
        int dead=person.isDead()?1:0;

        ContentValues values = new ContentValues();
        values.put(COLUMN_NAME, person.getName());
        values.put(COLUMN_REASON, person.getReason());
        values.put(COLUMN_STATUS,dead);
        values.put(COLUMN_FATE, person.getFate());
        values.put(COLUMN_HOUSE, person.getAllegiance());
        values.put(COLUMN_EXTRA, person.getExtra());
        values.put(COLUMN_IMG, person.getImg());

// Inserting Row
        db.insert(TABLE_NAME, null, values);
        db.close(); // Closing database connection
    }

    Hitlist getPerson(int id) {
        SQLiteDatabase db = this.getReadableDatabase();
        Hitlist person=null;

        Cursor cursor = db.query(
                TABLE_NAME,
                new String[] { COLUMN_ID, COLUMN_NAME, COLUMN_REASON, COLUMN_STATUS, COLUMN_FATE, COLUMN_HOUSE, COLUMN_EXTRA, COLUMN_IMG },
                COLUMN_ID + "=?",
                new String[] { String.valueOf(id) }, null, null, null, null);
        if (cursor != null){
            cursor.moveToFirst();
        //*************************
        boolean dead=(Integer.parseInt(cursor.getString(3))==0)?false:true;//DBHandler line number-102
        person = new Hitlist(Integer.parseInt(cursor.getString(0)),
                cursor.getString(1), cursor.getString(2), dead,
                cursor.getString(4), cursor.getString(5),
                cursor.getString(6), cursor.getString(7));

}
        return person;

    }


    public List<Hitlist> getAllPerssons() {
        List<Hitlist> persons = new ArrayList<Hitlist>();


        String selectQuery = "SELECT * FROM "+TABLE_NAME;

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);
        Hitlist person;

        if (cursor.moveToFirst()) {
            do {
                person = new Hitlist();
                person.setId(Integer.parseInt(cursor.getString(0)));
                person.setName(cursor.getString(1));
                person.setReason(cursor.getString(2));
                boolean dead= (Integer.parseInt(cursor.getString(3))==0)?false:true;
                person.setDead(dead);
                person.setFate(cursor.getString(4));
                person.setAllegiance(cursor.getString(5));
                person.setExtra(cursor.getString(6));
                person.setImg(cursor.getString(7));

                persons.add(person);
            } while (cursor.moveToNext());
        }

        db.close();

        return persons;

    }


    public int editPerson(Hitlist person) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(COLUMN_NAME, person.getName());
        values.put(COLUMN_REASON, person.getReason());
        values.put(COLUMN_STATUS,person.isDead());
        values.put(COLUMN_FATE, person.getFate());
        values.put(COLUMN_HOUSE, person.getAllegiance());
        values.put(COLUMN_EXTRA, person.getExtra());
        values.put(COLUMN_IMG, person.getImg());

// updating row
        return db.update(TABLE_NAME, values, COLUMN_ID + " = ?",
                new String[] { String.valueOf(person.getId()) });

    }

}

The VpagerAdapter class:

public class VpagerAdapter extends SmartFragmentStatePagerAdapter {

    private int pages=2;
    private DBHandler myDB;

    public VpagerAdapter(FragmentManager fm, DBHandler myDB){
        super(fm);
        this.myDB=myDB;
    }

    public int getPages() {
        return pages;
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }


    @Override
    public Fragment getItem(int position) {
        return fragment1.newInstance(position);
    }

    public void changePages(){pages++;}

    @Override
    public int getCount() {
        return pages;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        //***************************************
        return myDB.getPerson(position).getName();//This line 40 is showing error
    }
}

MainFragment class:

public class MainFragment extends Fragment{

    private ViewPager mPager;

    private VpagerAdapter mAdapter;

    static DBHandler myDB;

    static Hitlist person=new Hitlist();

    TabLayout myTabs;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myDB=DBHandler.getInstance(getActivity());
        if(myDB.getPersonsCount()==0){
            person=new Hitlist("Shruti","XYZ",false,null,null,null,"@drawable/arya");
            myDB.addPerson(person);
            person=new Hitlist("Rohan","TUV",false,null,null,null,"@drawable/arya2");
            myDB.addPerson(person);
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view=inflater.inflate(R.layout.main_fragment,container,false);
        mPager= (ViewPager) view.findViewById(R.id.ViewPager);
        mPager.setPageTransformer(true,new CubeOutTransformer());
        mAdapter=new VpagerAdapter(getActivity().getSupportFragmentManager(),myDB);
        mPager.setAdapter(mAdapter);
        myTabs= (TabLayout) view.findViewById(R.id.my_tabs);
        //********************************
        myTabs.setupWithViewPager(mPager);//MainFragment line no.48


        return view;
    }
}

I have specified which lines are showing the error in class by commenting beside it.

I have Initialised my DBHandler instance in MainActivity.java as this page advised to.

//In MainActivity.java, onCreate method()
myDB=DBHandler.getInstance(this);

EDIT-

I just noticed that if I call myDB.getPerson(int id) in MainActivity it works fine. Then the same error comes due to getPerson() being called in fragment1(the fragment which is provided to viewpager).When I called getPerson() in MainActivity, I also moved addition of data to database to MainActivity's onCreate

Why is this happening? The DB instance should be same everywhere. Whats changing that is making the app to crash?

EDIT#2- I also tried to call getPerson() in the MainFragment class and it still didn't show an error of cursor out of bounds. I dont know why is this happening.. The getPerson() in MainFragment was obviously called before the myTabs.setupWithViewPager(mPager) line

All suggestions are welcome. Thanks!

SOLUTION-

The problem was in getPageTitle() method of viewpager. I was passing position to method getPerson() that takes integer "ID" as parameter. The ID is indexed at 1 while position is indexed at 0. Just passing "position+1" instead of "position" to method call of getPageTitle() solved my problem. So, my cursor was not null it was empty, the query in getPerson() didn't fail, just that there were no rows in the query and I was trying to access one.


Solution

  • android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0

    This means, that Cursor is either null or it is empty i.e 0 rows in it.

    Hitlist getPerson(int id) {
        SQLiteDatabase db = this.getReadableDatabase();
    
        Cursor cursor = db.query(
                TABLE_NAME,
                new String[] { COLUMN_ID, COLUMN_NAME, COLUMN_REASON, COLUMN_STATUS, 
                COLUMN_FATE, COLUMN_HOUSE, COLUMN_EXTRA, COLUMN_IMG },
                COLUMN_ID + "=?",
                new String[] { String.valueOf(id) }, null, null, null, null);
    
        //Edit Part
        if (cursor != null && cursor.getCount()>0) {//perform operations on cursor only when 
                                                  //it is neither Null nor empty
                //another thing, you should check if moveToFirst() returns something or not
                Hitlist person;
                if (cursor.moveToFirst()) { //now here fetch things from cursor
                        boolean dead=(Integer.parseInt(cursor.getString(3))==0)?false:true;
                        person = new Hitlist(Integer.parseInt(cursor.getString(0)),
                        cursor.getString(1), cursor.getString(2), dead,
                        cursor.getString(4), cursor.getString(5),
                        cursor.getString(6), cursor.getString(7));
    
                        cursor.close();
                        return person;
                } else { 
                        cursor.close();
                        //print some message via Snackbar or Toast
                }
    
         } else { throw new Exception(); }
    
        cursor.close();
        throw new Exception();
    }