Pracuję nad integracją bazy danych, aby zapisać i zapisać podstawowe informacje kontaktowe, które będą pobierane w późniejszym czasie. Jednak moja aplikacja jest teraz upaść na starcie, więc nie mogę nawet sprawdzić, czy tabela jest tworzona itpUsterki aplikacji systemu Android podczas uruchamiania: SQLite NullPointerException w ContactsFragment
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, int, android.database.sqlite.SQLiteDatabase$CursorFactory, 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)
Kod Handler Baza:
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 mówi, że problem jest z SQLiteDatabase db = this.getWriteableDatabase();
Oto moja wykraczająca Contactsfragment także:
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, null, 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, null, null, 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, null, null, 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, dbPhone, status, 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);
}
Wreszcie, tutaj jest klasa ContactsDB:
public ContactsDb(String name, int phone, String status, String blurb) {
this._name = name;
this._phone = phone;
this._status = status;
this._blurb = blurb;
Każda pomoc jest mile widziane - Myślę, że problem tkwi w moim Kontekst jest zerowa. Po prostu nie jestem pewien, dlaczego byłby tak, jak to zdefiniowałem w moim pliku MyDBHandler. W tej chwili nie mam możliwości sprawdzenia, czy db jest tworzony, nie mówiąc już o przechowywaniu danych.
Cheers & Dzięki za poświęcony czas i cierpliwość, Shyam
Cześć Daniel, dzięki za szybką odpowiedź. Zrobiłem tę poprawkę, ale logcat nadal daje mi ten sam błąd. To ma dla mnie sens, jednak nigdy nie nazywam ContactsFragment (i daje mi to znać, mówiąc, że metoda o takiej nazwie może być łatwo pomylona jako konstruktor). Być może zachowuję mój ContactsDb jako taki i tworzę inny konstruktor ContactsFragment? – Shyam
Wow Daniel, świetny połów ... to był dokładnie problem. Odtąd zamknę to w mojej czaszce, że kontekst powinien być zadeklarowany w onCreate! Twoje zdrowie – Shyam