Search code examples
androidsqlitecursornullpointerexceptionandroid-listfragment

Am I working on the same database? getReadableDatabase() throws nullpointerexception


I'm new to android programming! I have a MainActivity in which the onCreate looks like this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    DBHandler db = new DBHandler(this);
    db.onUpgrade(db.getWritableDatabase(), 1, 2); // I have to figure out how to make the app create the database on install and not on app launch

    //Here all tables are filled up. It's hardcoded as the data is not intented to be changed by the user
    String ATABLENAME = "aTableName";
    db.addKeyPoint(new AKeyPoint(1, "sometext", 167, "areference"), ATABLENAME);
    db.addKeyPoint(new AKeyPoint(2, "someothertext", 0, "anotherreference"), ATABLENAME);
}

I also have an InitActivity, that launches upon the press of a button. Within this I have a ListFragment that implements LoaderManager.LoaderCallbacks:

public static class KeyFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
    private SimpleCursorAdapter adapter;    

    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);


        // the desired columns to be bound
        String[] columns = new String[] { "question1","answer1" };
        // the XML defined views which the data will be bound to
        int[] to = new int[] { R.id.question, R.id.answer };
        adapter = new SimpleCursorAdapter(getActivity(),R.layout.key_list_entry, null, columns, to, 0);       
        this.setListAdapter(adapter);

        LoaderManager lm = this.getLoaderManager();
        lm.initLoader(1, null, this);

    }

    public Loader<Cursor> onCreateLoader(int id, Bundle args) {

        final SimpleCursorLoader scloader = new SimpleCursorLoader(getActivity()) {
            @Override
            public Cursor loadInBackground() {
                final DBHandler db = new DBHandler(getActivity());
                Cursor c = db.getKeyPointCursor(1, "Crataegus");
                db.close();
                return c;
            }
        };
        return scloader;
    }

    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 
        adapter.swapCursor(cursor);
    }

    public void onLoaderReset(Loader<Cursor> loader) {
        adapter.swapCursor(null);       
    }    
}

}

I use the the SimpleCursorLoader with the LoaderManager. It can be found here: https://github.com/browep/AndroidCursorLoaderTutorial/blob/master/src/com/github/browep/cursorloader/SimpleCursorLoader.java . In my onCreateLoader the loadInBackGround retrieves a Cursor in the following way

Cursor c = db.getKeyPointCursor(anInt, "aTableName");

and returns it.

In my databasehandler (db) the getKeyPointCursor looks like this:

public Cursor getKeyPointCursor(int keyPointID, String tableName){
    Log.v("bae", "Now in getKeyPointCursor, attempting to get readable database");
    SQLiteDatabase db = this.getReadableDatabase();
    Log.v("bae", "Success... attempting to obtain a cursor");
    Cursor cursor = db.query(tableName, null, KEY_POINTID + "=?",
            new String[] { String.valueOf(keyPointID) }, null, null, null, null);
    Log.v("bae", "Success... closing db and returning cursor");
    db.close();
    return cursor;
}

It prints the "Now in getKeyPointCursor, attempting to get readable database" and then throws a NullPointerException:

09-19 19:27:39.920: W/dalvikvm(3055): threadid=11: thread exiting with uncaught exception (group=0x40c7c1f8)
09-19 19:27:39.925: E/AndroidRuntime(3055): FATAL EXCEPTION: ModernAsyncTask #1
09-19 19:27:39.925: E/AndroidRuntime(3055): java.lang.RuntimeException: An error occured while executing doInBackground()
09-19 19:27:39.925: E/AndroidRuntime(3055):     at android.support.v4.content.ModernAsyncTask$3.done(ModernAsyncTask.java:137)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at java.lang.Thread.run(Thread.java:856)
09-19 19:27:39.925: E/AndroidRuntime(3055): Caused by: java.lang.NullPointerException
09-19 19:27:39.925: E/AndroidRuntime(3055):     at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:157)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:231)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at jem.danskflora.DBHandler.getKeyPointCursor(DBHandler.java:235)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at jem.danskflora.InitKeyActivity$KeyFragment$1.loadInBackground(InitKeyActivity.java:79)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at jem.danskflora.SimpleCursorLoader.loadInBackground(SimpleCursorLoader.java:1)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(AsyncTaskLoader.java:240)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:51)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(AsyncTaskLoader.java:40)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at android.support.v4.content.ModernAsyncTask$2.call(ModernAsyncTask.java:123)
09-19 19:27:39.925: E/AndroidRuntime(3055):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
09-19 19:27:39.925: E/AndroidRuntime(3055):     ... 4 more

I'm suspecting that I'm not working on the same database somehow or maybe that I pass the wrong context to my databasehandler? Anyways I desperately need help to solve this!


Solution

  • I would say that the reason for that exception is this line:

    private DBHandler db = new DBHandler(getActivity());
    

    at that moment getActivity() most likely returns null as the Fragment isn't attached yet and this Context reference is used in the getReadableDatabase() and getWritableDatabase() methods. Try to initialize the db reference from the KeyFragment in onActivityCreated, the Activity reference will be available there.

    Also, avoid this:

    db.onUpgrade(db.getWritableDatabase(), 1, 2);