我正在集成数据库来保存和存储以后要检索的基本联系信息.但是,我的应用程序现在在启动时崩溃,所以我甚至无法验证是否正在创建表等.
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); } //........