我正在集成数据库来保存和存储以后要检索的基本联系信息.但是,我的应用程序现在在启动时崩溃,所以我甚至无法验证是否正在创建表等.
- 05-05 16:39:50.671 11631-11631/treehouse.greenlight E/AndroidRuntime﹕ FATAL EXCEPTION: main
- Process: treehouse.greenlight,PID: 11631
- java.lang.RuntimeException: Unable to start activity ComponentInfo{treehouse.greenlight/treehouse.greenlight.Home_screen}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.sqliteDatabase android.content.Context.openOrCreateDatabase(java.lang.String,int,android.database.sqlite.sqliteDatabase$CursorFactory,android.database.DatabaseErrorHandler)' on a null object reference
- at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2205)
- at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2255)
- at android.app.ActivityThread.access$800(ActivityThread.java:142)
- at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1203)
- at android.os.Handler.dispatchMessage(Handler.java:102)
- at android.os.Looper.loop(Looper.java:136)
- at android.app.ActivityThread.main(ActivityThread.java:5118)
- at java.lang.reflect.Method.invoke(Native Method)
- at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
- at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:610)
- Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.sqliteDatabase android.content.Context.openOrCreateDatabase(java.lang.String,android.database.DatabaseErrorHandler)' on a null object reference
- at android.database.sqlite.sqliteOpenHelper.getDatabaseLocked(sqliteOpenHelper.java:224)
- at android.database.sqlite.sqliteOpenHelper.getWritableDatabase(sqliteOpenHelper.java:164)
- at treehouse.greenlight.MyDBHandler.addContact(MyDBHandler.java:54)
- at treehouse.greenlight.ContactsFragment.onCreateLoader(ContactsFragment.java:117)
- at android.support.v4.app.LoaderManagerImpl.createLoader(LoaderManager.java:490)
- at android.support.v4.app.LoaderManagerImpl.createAndInstallLoader(LoaderManager.java:499)
- at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:553)
- at treehouse.greenlight.ContactsFragment.onActivityCreated(ContactsFragment.java:71)
- at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1797)
- at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:979)
- at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1138)
- at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1120)
- at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1929)
- at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
- at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
- at android.app.Activity.performStart(Activity.java:5285)
- at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2178)
- public class MyDBHandler extends sqliteOpenHelper {
- private static final int DATABASE_VERSION = 1;
- private static final String DATABASE_NAME = "contactsDB.db";
- public static final String TABLE_CONTACTS = "contacts";
- private Context context;
- public static final String COLUMN_ID = "_id";
- public static final String COLUMN_NAME = "name";
- public static final String COLUMN_PHONE = "phone";
- public static final String COLUMN_STATUS = "status";
- public static final String COLUMN_BLURB = "blurb";
- public MyDBHandler(Context context,String name,CursorFactory factory,int version) {
- super(context,DATABASE_NAME,factory,DATABASE_VERSION);
- }
- @Override
- public void onCreate (sqliteDatabase db){
- String CREATE_CONTACTS_TABLE = "CREATE TABLE " +
- TABLE_CONTACTS + "("
- + COLUMN_ID + " INTEGER PRIMARY KEY," + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
- + " TEXT," + ContactsContract.CommonDataKinds.Phone.NUMBER + " INTEGER,"
- + COLUMN_STATUS + " TEXT," + COLUMN_BLURB
- + " TEXT" + ");";
- db.execsql(CREATE_CONTACTS_TABLE);
- }
- @Override
- public void onUpgrade (sqliteDatabase db,int oldVersion,int newVersion){
- db.execsql("DROP TABLE IF EXISTS " + TABLE_CONTACTS);
- onCreate(db);
- }
- public void addContact(ContactsDb contacts) {
- ContentValues values = new ContentValues();
- values.put(COLUMN_NAME,contacts.getName());
- values.put(COLUMN_PHONE,contacts.getPhone());
- values.put(COLUMN_STATUS,contacts.getStatus());
- values.put(COLUMN_BLURB,contacts.getBlurb());
- sqliteDatabase db = this.getWritableDatabase();
- db.insert(TABLE_CONTACTS,null,values);
- }
logcat说问题是sqliteDatabase db = this.getWriteableDatabase();
这也是我违规的Contactsfragment:
- public class ContactsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
- private CursorAdapter mAdapter;
- private Context context;
- TextView idView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // create adapter once
- Context context = getActivity();
- int layout = R.layout.activity_list_item_1;
- Cursor c = null; // there is no cursor yet
- int flags = 0; // no auto-requery! Loader requeries.
- mAdapter = new SimpleCursorAdapter(context,layout,c,FROM,TO,flags);
- }
- public void ContactsDb(Context context) {
- this.context=context;
- }
- Uri contentUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
- String[] PROJECTION = {
- ContactsContract.Contacts.HAS_PHONE_NUMBER,ContactsContract.Contacts._ID,// _ID is always required
- ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY,// that is what we want to display
- Contacts.TIMES_CONTACTED,ContactsContract.CommonDataKinds.Phone.NUMBER
- };
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- // each time we are started use our listadapter
- setListAdapter(mAdapter);
- // and tell loader manager to start loading
- getLoaderManager().initLoader(0,this);
- }
- // columns requested from the database
- // and name should be displayed in the text1 textview in item layout
- public String[] has_phone = {ContactsContract.Contacts.HAS_PHONE_NUMBER};
- String phone = "0";
- int dbPhone = 0;
- private final String[] FROM = {Contacts.DISPLAY_NAME_PRIMARY,ContactsContract.CommonDataKinds.Phone.NUMBER};
- private final int[] TO = {android.R.id.text1,dbPhone};
- public void newContact (View view) {
- MyDBHandler dbHandler = new MyDBHandler(context,1);
- String name = Contacts.DISPLAY_NAME_PRIMARY;
- int dbPhone =
- Integer.parseInt(phone);
- String status ="";
- String blurb ="";
- ContactsDb contacts =
- new ContactsDb(name,dbPhone,status,blurb);
- dbHandler.addContact(contacts);
- }
- @Override
- public Loader<Cursor> onCreateLoader(int id,Bundle args) {
- Context context = this.context;
- // load from the "Contacts table"
- MyDBHandler dbHandler = new MyDBHandler(context,1);
- String name = Contacts.DISPLAY_NAME_PRIMARY;
- int phone = Integer.parseInt(ContactsContract.CommonDataKinds.Phone.NUMBER);
- String status ="Busy";
- String blurb ="N/A";
- ContactsDb contacts =
- new ContactsDb(name,blurb);
- dbHandler.addContact(contacts);
- // no sub-selection,no sort order,simply every row
- // projection says we want just the _id and the name column
- return new CursorLoader(getActivity(),contentUri,PROJECTION,ContactsContract.Contacts.HAS_PHONE_NUMBER + " =? AND " + Contacts.TIMES_CONTACTED + ">=?",// This is selection string,we're looking for records that HAS_PHONE_NUMBER is 1
- new String[]{"1","0"},// 1 means that contact has a phone number & 60 is the amount of times contacted (arbitrary - needs to be fixed before release)
- null);
- }
最后,这是ContactsDB类:
- public ContactsDb(String name,int phone,String status,String blurb) {
- this._name = name;
- this._phone = phone;
- this._status = status;
- this._blurb = blurb;
非常感谢任何帮助 – 我认为问题在于我的Context为null.我只是不确定为什么它会在我的MyDBHandler文件中定义它.截至目前,我无法验证是否正在创建数据库,更不用说保存数据了.
干杯&感谢您的时间和耐心,
希亚姆
解决方法
看起来你不小心创建了一个上下文局部变量而不是使用实例变量.
因此,当您将其传递给MyDBHandler时,context为null,因此当您调用this.getWritableDatabase()时,它为null.因此,您可以在日志中看到NullPointerException:
- Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.sqlite.sqliteDatabase android.content.Context.openOrCreateDatabase(java.lang.String,android.database.DatabaseErrorHandler)' on a null object reference
- at android.database.sqlite.sqliteOpenHelper.getDatabaseLocked(sqliteOpenHelper.java:224)
- at android.database.sqlite.sqliteOpenHelper.getWritableDatabase(sqliteOpenHelper.java:164)
尝试将所有与Context相关的代码移动到onActivityCreated()以确保您具有有效的Context,并确保使用实例变量而不是局部变量:
- public class ContactsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
- private CursorAdapter mAdapter;
- private Context context; //this is the Context you will use
- TextView idView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // create adapter once
- //Context context = getActivity(); //Here was the problem
- //int layout = R.layout.activity_list_item_1;
- //Cursor c = null; // there is no cursor yet
- //int flags = 0; // no auto-requery! Loader requeries.
- //mAdapter = new SimpleCursorAdapter(context,ContactsContract.CommonDataKinds.Phone.NUMBER
- };
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- //Add this here:
- context = getActivity(); //use the instance variable
- int layout = R.layout.activity_list_item_1;
- Cursor c = null; // there is no cursor yet
- int flags = 0; // no auto-requery! Loader requeries.
- mAdapter = new SimpleCursorAdapter(context,flags);
- // each time we are started use our listadapter
- setListAdapter(mAdapter);
- // and tell loader manager to start loading
- getLoaderManager().initLoader(0,dbPhone};
- public void newContact (View view) {
- //context should now be valid:
- MyDBHandler dbHandler = new MyDBHandler(context,blurb);
- dbHandler.addContact(contacts);
- }
- //........