I have a dictionary app which stores a word with the meaning, type (English,Chinese,Japanese etc) and favorite status (whether it's a favorite word). On 1 of my menu items, there's this item called sort. When I click on it, I am expecting the words in my main page to be sorted in ascending order but instead I got this error in ListFragment.java: 'java.lang.IllegalStateException: Couldn't read row 0, col 4 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.'. There's nothing wrong with my database.
MainActivity.java
package mapp.com.sg.pocketdictionary; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.content.Intent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import mapp.com.sg.pocketdictionary.db.WordsDataSource; public class MainActivity extends AppCompatActivity implements ListFragment.OnContactSelectedInterface/*,SearchView.OnQueryTextListener*/ { protected WordsDataSource myDataSource; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myDataSource = new WordsDataSource(this); this.setTitle("PD"); //The code here decides whether to create the fragment because it can be destroyed by the Android system //when it reclaims memory ListFragment savedFragment = (ListFragment) getSupportFragmentManager().findFragmentByTag("WORDS_FRAGMENT"); if (savedFragment == null) { ListFragment fragment = new ListFragment(); Bundle bundle = new Bundle(); bundle.putBoolean("isFavourite", false); fragment.setArguments(bundle); android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager(); android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.add(R.id.placeHolder, fragment, "WORDS_FRAGMENT"); fragmentTransaction.commit(); } } @Override protected void onResume() { //The code here is required because when I save the data and navigate back //I need my applicationn logic to refresh the fragement content to reflect the changes //to avoid the list interface listing the old data. super.onResume(); ListFragment savedFragment = (ListFragment) getSupportFragmentManager().findFragmentByTag("WORDS_FRAGMENT"); if (savedFragment != null) { android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager(); android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.detach(savedFragment); fragmentTransaction.attach(savedFragment); fragmentTransaction.commit(); } } @Override public void onListContactSelected(int index) { //When tap on a row display word, this logic here will start collecting the //id which is tied to the data and navigate the user to another Activity //and at the same time pass the id over. // Toast.makeText(this, "PUMPKINNNNNN", Toast.LENGTH_SHORT).show(); for testing if tap detected Intent intent = new Intent(this, WordsDetailActivity.class); intent.putExtra("WordId", index);//index variable name may not be suitable here startActivity(intent); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater myMenuInflater = getMenuInflater(); myMenuInflater.inflate(R.menu.menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { String itemTitle = item.getTitle().toString(); if (item.getItemId() == R.id.favourite) { // Toast.makeText(this, "GER" , Toast.LENGTH_SHORT).show();//Go to favorite action choice detected startActivity(new Intent(this, FavouriteActivity.class)); } else if (item.getItemId() == R.id.Add) { // Toast.makeText(this, "EEEEYEERR", Toast.LENGTH_SHORT).show();//Go to add word action choice detected startActivity(new Intent(this, AddWordsActivity.class)); } else if (item.getItemId() == R.id.sort) { Bundle bundle = new Bundle(); bundle.putBoolean("isSortByAsc", true); ListFragment savedFragment = (ListFragment) getSupportFragmentManager().findFragmentByTag("WORDS_FRAGMENT"); if (savedFragment != null) { savedFragment.setArguments(bundle); android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager(); android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.detach(savedFragment); fragmentTransaction.attach(savedFragment); fragmentTransaction.commit(); } } } return super.onOptionsItemSelected(item); } }
ListFragment.java
package mapp.com.sg.pocketdictionary; import android.database.Cursor; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import mapp.com.sg.pocketdictionary.db.WordsDataSource; public class ListFragment extends Fragment { protected WordsDataSource mDataSource; private boolean isFavourite; private boolean isSortByAsc; public interface OnContactSelectedInterface { void onListContactSelected(int index); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { OnContactSelectedInterface listener = (OnContactSelectedInterface) getActivity(); isFavourite = getArguments().getBoolean("isFavourite"); isSortByAsc = getArguments().getBoolean("isSortByAsc"); View view = inflater.inflate(R.layout.fragment_recycler, container,false); //------------------- //The rest of the code below is to read all or favorite word data //and fill up the ArrayList variable. mDataSource = new WordsDataSource(getContext()); mDataSource.open(); Cursor cursor; if(isFavourite){ cursor = mDataSource.selectFavouriteWords(); } else if (isSortByAsc){ cursor = mDataSource.sortWords(); } else{ cursor = mDataSource.selectAllWords(); } ArrayList<Words> wordsList = new ArrayList<>(); cursor.moveToFirst(); while(!cursor.isAfterLast()){ boolean tempFav = true;//The database uses 0 and 1 to represent true or false //Therefore I used this tempFav so that my logic here can store true or false //during the getString() call //Error occurs here if (cursor.getInt(4) != 0) { tempFav = false; } Words tempWords =new Words(cursor.getString(1),cursor.getString(2),cursor.getString(3),tempFav); tempWords.setId(cursor.getInt(0)); wordsList.add(tempWords); //Log.d("MY Activity", "onCreateView: "+ tempWords.getId()+" " + tempWords.getWord()+" " +tempWords.getMeaning()+" "+ tempWords.getType()+" "+ cursor.getInt(4)); Log.d("MY Activity", "cursor: "+ cursor.getInt(0)+ " "+cursor.getString(1)+" " + cursor.getString(2)+" "+cursor.getString(3)+" " + cursor.getInt(4)); //Column 0 is id, column 1 is word, column 2 is meaning, column 3 is type, column 4 is favorite status(0 for true and 1 for false) cursor.moveToNext(); } mDataSource.close(); //----------------------- //After the ArrayList variable is filled with data, //create a listAdapter type object RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); //Creating a ListAdapter object and at the same time pass in a "walkie-talkie" so that it can //yell out if any related events happening and also the ArrayList of contect information ListAdapter listAdapter = new ListAdapter(listener, wordsList); recyclerView.setAdapter(listAdapter);//Start using it RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(layoutManager); return view; } }
WordsDataSource.java
package mapp.com.sg.pocketdictionary.db; //insert update delete import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.util.Log; import mapp.com.sg.pocketdictionary.Words; public class WordsDataSource { private SQLiteDatabase mDatabase; private WordsHelper mWordsHelper; private Context mContext; public WordsDataSource(Context context){ mContext = context; mWordsHelper = new WordsHelper(mContext); } //open data base public void open() throws SQLException { mDatabase = mWordsHelper.getWritableDatabase(); } //close public void close() { mDatabase.close(); } //insert public void insertWords(Words words) { mDatabase.beginTransaction(); try{ ContentValues values = new ContentValues(); values.put(WordsHelper.COLUMN_WORD, words.getWord()); values.put(WordsHelper.COLUMN_MEANING, words.getMeaning()); values.put(WordsHelper.COLUMN_TYPE, words.getType()); int fav = 0; if (!words.isFavourite()) { fav = 1; } values.put(WordsHelper.COLUMN_FAVOURITE, fav); mDatabase.insert(WordsHelper.TABLE_WORDS, null, values); mDatabase.setTransactionSuccessful(); } finally { mDatabase.endTransaction(); } } //sort public Cursor sortWords (){ String[] wordname = new String[]{ WordsHelper.COLUMN_WORD }; Cursor cursor= mDatabase.query(WordsHelper.TABLE_WORDS,wordname , null, null, null, null, WordsHelper.COLUMN_WORD+" ASC"); return cursor; } //select public Cursor selectAllWords(){ Cursor cursor = mDatabase.rawQuery("Select * from " + WordsHelper.TABLE_WORDS, null); return cursor; } public Cursor selectOneWord(int Id){ Cursor cursor = mDatabase.rawQuery("Select * from " + WordsHelper.TABLE_WORDS+" where " + WordsHelper.COLUMN_ID+" = " + Id, null); return cursor; } public Cursor selectFavouriteWords() { Cursor cursor = mDatabase.rawQuery("Select * from " + WordsHelper.TABLE_WORDS+" where " + WordsHelper.COLUMN_FAVOURITE+" = 0" , null); return cursor; } //update public boolean updateWords(int id, String word, String meaning,String type, boolean fav){ ContentValues values = new ContentValues(); int success = -1; values.put(WordsHelper.COLUMN_WORD, word); values.put(WordsHelper.COLUMN_MEANING, meaning); values.put(WordsHelper.COLUMN_TYPE, type); int favDigit = 0; if(!fav){ favDigit = 1; } values.put(WordsHelper.COLUMN_FAVOURITE, favDigit); success = mDatabase.update( WordsHelper.TABLE_WORDS, values, WordsHelper.COLUMN_ID + " = " + id, null ); if(success != -1 && success != 0) { return true; } else { return false; } } public boolean setFavourite (int id, boolean fav) { ContentValues values = new ContentValues(); int success = -1; int favDigit = 0; if(!fav){ favDigit = 1; } values.put(WordsHelper.COLUMN_FAVOURITE, favDigit); success = mDatabase.update( WordsHelper.TABLE_WORDS, values, WordsHelper.COLUMN_ID + " = " + id, null ); if(success != -1 && success != 0) { return true; } else { return false; } } public boolean updateWords(int id, String word, String meaning,String type){ ContentValues values = new ContentValues(); int success = -1; if(word != null ){ values.put(WordsHelper.COLUMN_WORD, word); } if(meaning != null ){ values.put(WordsHelper.COLUMN_MEANING, meaning); } if(type != null ){ values.put(WordsHelper.COLUMN_TYPE, type); } success = mDatabase.update( WordsHelper.TABLE_WORDS, values, WordsHelper.COLUMN_ID + " = " + id, null ); if(success != -1 && success != 0) { return true; } else { return false; } } //delete public boolean deleteWords(int id) { int success = -1; success = mDatabase.delete( WordsHelper.TABLE_WORDS, WordsHelper.COLUMN_ID + " = " + id, null ); if(success != -1 && success !=0) { return true; } else { return false; } } public boolean deleteWords() { int success = -1; success = mDatabase.delete( WordsHelper.TABLE_WORDS, null, null ); if(success != -1 ) { return true; } else { return false; } } }
WordsHelper.java
package mapp.com.sg.pocketdictionary.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; //Helps make all code in WordsDataSource neater, readable and maintainable. public class WordsHelper extends SQLiteOpenHelper { public static final String TABLE_WORDS ="WORDS"; public static final String COLUMN_ID = "_ID"; public static final String COLUMN_WORD = "WORD"; public static final String COLUMN_MEANING = "MEANING"; public static final String COLUMN_TYPE = "TYPE"; public static final String COLUMN_FAVOURITE = "FAVOURITE"; private static final String DB_NAME = "words.db"; private static final int DB_VER = 1; private static final String DB_CREATE = "CREATE TABLE "+TABLE_WORDS+ " (" + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT" + ", " + COLUMN_WORD + " TEXT, " + COLUMN_MEANING + " TEXT,"+ COLUMN_TYPE + " TEXT,"+ COLUMN_FAVOURITE +" INTEGER)"; public WordsHelper(Context context){ super(context, DB_NAME, null, DB_VER); } @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { sqLiteDatabase.execSQL(DB_CREATE); } @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { } }