我的 Android 应用程序中有数据库问题,我似乎无法弄清楚。我在我的代码中看不到任何错误,但是当我运行应用程序时,应用程序崩溃,LogCat 指向我的代码中的多个点。其中包括:NullPointerExceptions 和 SQLiteOpenHelper(在 .getWritableDatabase 上)。
Notifications.java类的onCreate方法和NotificationsDbAdapter.java类的open方法中的代码似乎有问题。
代码文件和 LogCat 错误日志如下所示。
我该如何解决这个问题?任何帮助将不胜感激?
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错误日志
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