简体   繁体   English

打开SQLite数据库(在内部数据库适配器中)会使Android App崩溃

[英]Opening SQLite database (in inner database adapter) crashes an Android App

I have database problem in my Android app that I can't seem to figure out. 我的Android应用程序中有数据库问题,我似乎无法弄清楚。 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. 我的代码没有看到任何错误,但是当我运行该应用程序时,该应用程序崩溃,并且LogCat指向我的代码中的多个点。 Among these are: NullPointerExceptions and SQLiteOpenHelper (on .getWritableDatabase). 其中包括:NullPointerExceptions和SQLiteOpenHelper(在.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. 似乎是在Notifications.java类的onCreate方法的代码,另一个在NotificationsDbAdapter.java类的开放式方法的问题。

The code files and the LogCat error log are shown below. 代码文件和LogCat错误日志如下所示。

How do I solve this? 我该如何解决? Any help will be highly appreciated? 任何帮助将不胜感激?


1. Notifications.java 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 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 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 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

The Context you passed to SQLiteOpenHelper super constructor was null . 您传递给SQLiteOpenHelper超级构造函数的Contextnull This explains the stacktrace. 这解释了堆栈跟踪。

The Context is null because mCtx is not initialized. Context为空,因为未初始化mCtx It would be initialized in this method you never call: 它将用您从未调用过的此方法初始化:

public void notificationsDbAdapter(Context ctx) {
    this.mCtx = ctx;
}

Change it to a constructor: 将其更改为构造函数:

public NotificationsDbAdapter(Context ctx) {
    this.mCtx = ctx;
}

And update the references to pass in a Context , eg: 并更新引用以传递Context ,例如:

new NotificationsDbAdapter(this)

You are calling the wrong constructor of the NotificationsDbAdapter class: 您正在调用NotificationsDbAdapter类的错误构造函数:

    mDbHelper = new NotificationsDbAdapter();

You must use the constructor with the Context parameter; 您必须将构造函数与Context参数一起使用; otherwise, the context object is null , and you get the NullPointerException. 否则,上下文对象为null ,您将获得NullPointerException。

The parameter-less constructor is created automatically by the Java compiler because the base class ( Object ) has one. 由于基类( Object )具有一个,因此无参数构造函数由Java编译器自动创建。 To prevent it from being used accidentally, create your own, but make it private: 为防止意外使用它,请创建自己的,但将其设为私有:

private NotificationsDbAdapter() {
    // never called
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM