I have database problem in my Android app that I can't seem to figure out. I do not see any errors in my code but when I run the application, the app crashes with LogCat pointing to multiple points in my code. Among these are: NullPointerExceptions and SQLiteOpenHelper (on .getWritableDatabase).
There seems to be a problem with the code in the onCreate method of Notifications.java Class and another one in the open method in NotificationsDbAdapter.java class.
The code files and the LogCat error log are shown below.
How do I solve this? Any help will be highly appreciated?
1. Notifications.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notification_list);
mDbHelper = new NotificationsDbAdapter();
mDbHelper.open();
fillData();
registerForContextMenu(getListView());
}
@SuppressWarnings("deprecation")
private void fillData() {
Cursor notificationsCursor = mDbHelper.fetchAllNotifications();
startManagingCursor(notificationsCursor);
// Create an array to specify the fields we want (only the TITLE)
String[] from = new String[]{NotificationsDbAdapter.KEY_TITLE};
// and an array of the fields we want to bind in the view
int[] to = new int[]{R.id.notifytext};
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter notifications =
new SimpleCursorAdapter(this, R.layout.notify_row, notificationsCursor, from, to);
setListAdapter(notifications);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.notify_list, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_add_notify:
createReminder();
return true;
case android.R.id.home:
finish();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
private void createReminder() {
Intent i = new Intent(this, NotificationEditor.class);
startActivityForResult(i, ACTIVITY_CREATE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
fillData();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent i = new Intent(this, NotificationEditor.class);
i.putExtra(NotificationsDbAdapter.KEY_ROWID, id);
startActivityForResult(i, ACTIVITY_EDIT);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater mi = getMenuInflater();
mi.inflate(R.menu.ctx_notify_delete, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.notify_delete:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
mDbHelper.deleteNotification(info.id);
fillData();
return true;
}
return super.onContextItemSelected(item);
}
}
tring dateForButton = dateFormat.format(mCalendar.getTime());
mDateButton.setText(dateForButton);
}
private void updateTimeButtonText() {
SimpleDateFormat timeFormat = new SimpleDateFormat(TIME_FORMAT);
String timeForButton = timeFormat.format(mCalendar.getTime());
mTimeButton.setText(timeForButton);
}
}
2. NotificationEditor.java
;
private long mRowId;
private Calendar mCalendar;
private Button mDateButton;
private Button mTimeButton;
private EditText mTitleText;
private EditText mDescText;
private Button mSaveButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDbHelper = new NotificationsDbAdapter();
setContentView(R.layout.notification_editor);
mCalendar = Calendar.getInstance();
mDateButton = (Button) findViewById(R.id.notify_date);
mTimeButton = (Button) findViewById(R.id.notify_time);
mSaveButton = (Button) findViewById(R.id.notify_save);
mTitleText = (EditText) findViewById(R.id.title);
mDescText = (EditText) findViewById(R.id.descri);
mRowId = savedInstanceState != null
? savedInstanceState.getLong(NotificationsDbAdapter.KEY_ROWID)
: null;
registerButtonListenersAndSetDefaultText();
}
private void setRowIdFromIntent() {
if (mRowId == 0L) {
Bundle extras = getIntent().getExtras();
mRowId = extras != null
? extras.getLong(NotificationsDbAdapter.KEY_ROWID)
: null;
}
}
@Override
protected void onResume() {
super.onResume();
mDbHelper.open();
setRowIdFromIntent();
try {
populateFields();
} catch (java.text.ParseException e) {
e.printStackTrace();
}
}
@Override
protected void onPause() {
super.onPause();
mDbHelper.close();
}
private void registerButtonListenersAndSetDefaultText() {
mDateButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDialog(DATE_PICKER_DIALOG);
}
});
mTimeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDialog(TIME_PICKER_DIALOG);
}
});
updateDateButtonText();
updateTimeButtonText();
mSaveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
saveState();
setResult(RESULT_OK);
Toast.makeText(NotificationEditor.this,
getString(R.string.txt_reminder_saved_message),
Toast.LENGTH_SHORT).show();
finish();
}
private void saveState() {
String title = mTitleText.getText().toString();
String description = mDescText.getText().toString();
SimpleDateFormat dateTimeFormat = new
SimpleDateFormat(DATE_TIME_FORMAT);
String notificationDateTime = dateTimeFormat.format(mCalendar.getTime());
if (mRowId == 0L) {
long id = mDbHelper.createNotification(title, description, notificationDateTime);
if (id > 0) {
mRowId = id;
}
} else {
mDbHelper
.updateNotification(mRowId, title, description, notificationDateTime);
}
}
});
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong(NotificationsDbAdapter.KEY_ROWID, mRowId);
}
@Override
protected Dialog onCreateDialog(int id) {
switch(id) {
case DATE_PICKER_DIALOG:
return showDatePicker();
case TIME_PICKER_DIALOG:
return showTimePicker();
}
return super.onCreateDialog(id);
}
private DatePickerDialog showDatePicker() {
DatePickerDialog datePicker = new DatePickerDialog(NotificationEditor.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
mCalendar.set(Calendar.YEAR, year);
mCalendar.set(Calendar.MONTH, monthOfYear);
mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateDateButtonText();
}
}, mCalendar.get(Calendar.YEAR), mCalendar.get(Calendar.MONTH),
mCalendar.get(Calendar.DAY_OF_MONTH));
return datePicker;
}
private TimePickerDialog showTimePicker() {
TimePickerDialog timePicker = new TimePickerDialog(this, new
TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute){
mCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
mCalendar.set(Calendar.MINUTE, minute);
updateTimeButtonText();
}
}, mCalendar.get(Calendar.HOUR_OF_DAY),
mCalendar.get(Calendar.MINUTE), true);
return timePicker;
}
private void populateFields() throws java.text.ParseException {
if (mRowId != 0L) {
Cursor notification = mDbHelper.fetchNotification(mRowId);
startManagingCursor(notification);
mTitleText.setText(notification.getString(
notification.getColumnIndexOrThrow(NotificationsDbAdapter.KEY_TITLE)));
mDescText.setText(notification.getString(
notification.getColumnIndexOrThrow(NotificationsDbAdapter.KEY_DESC)));
SimpleDateFormat dateTimeFormat =
new SimpleDateFormat(DATE_TIME_FORMAT);
Date date = null;
try {
String dateString = notification.getString(
notification.getColumnIndexOrThrow(
NotificationsDbAdapter.KEY_DATE_TIME));
date = dateTimeFormat.parse(dateString);
mCalendar.setTime(date);
} catch (ParseException e) {
Log.e("NotificationEditor", e.getMessage(), e);
}
}
}
private void updateDateButtonText() {
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
String dateForButton = dateFormat.format(mCalendar.getTime());
mDateButton.setText(dateForButton);
}
private void updateTimeButtonText() {
SimpleDateFormat timeFormat = new SimpleDateFormat(TIME_FORMAT);
String timeForButton = timeFormat.format(mCalendar.getTime());
mTimeButton.setText(timeForButton);
}
}
3. NotificationsDbAdapter.java
public class NotificationsDbAdapter {
private static final String DATABASE_NAME = "mpegdb";
private static final String DATABASE_TABLE = "notifications";
private static final int DATABASE_VERSION = 1;
public static final String KEY_TITLE = "title";
public static final String KEY_DESC = "description";
public static final String KEY_DATE_TIME = "notification_date_time";
public static final String KEY_ROWID = "_id";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static final String DATABASE_CREATE =
"create table " + DATABASE_TABLE + " ("
+ KEY_ROWID + " integer primary key autoincrement, "
+ KEY_TITLE + " text not null, "
+ KEY_DESC + " text not null, "
+ KEY_DATE_TIME + " text not null);";
private Context mCtx;
public void notificationsDbAdapter(Context ctx) {
this.mCtx = ctx;
}
public NotificationsDbAdapter open() throws android.database.SQLException {
Log.i(LOGTAG, "Database opened");
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
Log.i(LOGTAG, "Database closed");
mDbHelper.close();
}
public long createNotification(String title, String description, String
notificationDateTime) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_TITLE, title);
initialValues.put(KEY_DESC, description);
initialValues.put(KEY_DATE_TIME, notificationDateTime);
return mDb.insert(DATABASE_TABLE, null, initialValues);
}
public boolean deleteNotification(long rowId) {
return
mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}
public Cursor fetchAllNotifications() {
return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_TITLE,
KEY_DESC, KEY_DATE_TIME}, null, null, null, null, null);
}
public Cursor fetchNotification(long rowId) throws SQLException {
Cursor mCursor =
mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
KEY_TITLE, KEY_DESC, KEY_DATE_TIME}, KEY_ROWID + "=" +
rowId, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
public boolean updateNotification(long rowId, String title, String description, String
notificationDateTime) {
ContentValues args = new ContentValues();
args.put(KEY_TITLE, title);
args.put(KEY_DESC, description);
args.put(KEY_DATE_TIME, notificationDateTime);
return
mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
}
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
Log.i(LOGTAG, "Table created");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
onCreate(db);
}
}
}
4. LogCat Error log
06-10 11:53:24.056: E/AndroidRuntime(8663): FATAL EXCEPTION: main
06-10 11:53:24.056: E/AndroidRuntime(8663): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tbk.mpeg/com.tbk.mpeg.Notifications}: java.lang.NullPointerException
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2114)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2139)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.app.ActivityThread.access$700(ActivityThread.java:143)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1241)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.os.Handler.dispatchMessage(Handler.java:99)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.os.Looper.loop(Looper.java:137)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.app.ActivityThread.main(ActivityThread.java:4963)
06-10 11:53:24.056: E/AndroidRuntime(8663): at java.lang.reflect.Method.invokeNative(Native Method)
06-10 11:53:24.056: E/AndroidRuntime(8663): at java.lang.reflect.Method.invoke(Method.java:511)
06-10 11:53:24.056: E/AndroidRuntime(8663): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
06-10 11:53:24.056: E/AndroidRuntime(8663): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
06-10 11:53:24.056: E/AndroidRuntime(8663): at dalvik.system.NativeStart.main(Native Method)
06-10 11:53:24.056: E/AndroidRuntime(8663): Caused by: java.lang.NullPointerException
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
06-10 11:53:24.056: E/AndroidRuntime(8663): at com.tbk.mpeg.database.NotificationsDbAdapter.open(NotificationsDbAdapter.java:40)
06-10 11:53:24.056: E/AndroidRuntime(8663): at com.tbk.mpeg.Notifications.onCreate(Notifications.java:32)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.app.Activity.performCreate(Activity.java:5184)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
06-10 11:53:24.056: E/AndroidRuntime(8663): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2078)
06-10 11:53:24.056: E/AndroidRuntime(8663): ... 11 more