6

Ich arbeite an der Integration einer Datenbank zum Speichern und Speichern von grundlegenden Kontaktinformationen zu einem späteren Zeitpunkt abgerufen werden. Allerdings ist meine App jetzt beim Start abstürzt, so kann ich nicht einmal überprüfen, ob die Tabelle erstellt wird, usw.Android App stürzt beim Start ab: SQLite NullPointerException in 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)  

Database Handler Code:

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); 

} 

Die logcat sagt das Problem mit SQLiteDatabase db = this.getWriteableDatabase(); ist

Hier ist mein säumiges Contactsfragment auch:

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); 
} 

Schließlich ist hier die ContactsDB Klasse:

public ContactsDb(String name, int phone, String status, String blurb) { 

    this._name = name; 
    this._phone = phone; 
    this._status = status; 
    this._blurb = blurb; 

Jede Hilfe sehr geschätzt wird - ich glaube, das Problem liegt mit meinem Kontext null zu sein. Ich bin nur nicht sicher, warum es so wäre, wie ich es in meiner MyDBHandler-Datei definiert habe. Im Moment habe ich keine Möglichkeit zu überprüfen, ob die Datenbank erstellt wird, geschweige denn Daten.

Prost & Vielen Dank für Ihre Zeit und Geduld, Shyam

Antwort

12

Es sieht aus wie Sie versehentlich eine context lokale Variable erstellt stattdessen die Instanz-Variable zu verwenden.

So context ist null, wenn Sie es in MyDBHandler passieren, also wenn Sie this.getWritableDatabase() nennen, this ist null. Als Ergebnis erhalten Sie die NullPointerException, wie im Protokoll sehen:

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) 

Versuchen Sie, alle die Context bewegenden Code onActivityCreated() bezogen Sie eine gültige Context haben, um sicherzustellen, und stellen Sie sicher, dass die Instanz-Variable zu verwenden, anstelle einer lokalen Variablen:

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, 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); 

    //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, layout, c, FROM, TO, flags); 

    // 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) { 

    //context should now be valid: 
    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); 

} 
//........ 
+0

Hallo Daniel, danke für die prompte Antwort. Ich habe diese Korrektur gemacht, aber der Logcat gibt mir immer noch den gleichen Fehler. Das macht für mich Sinn, allerdings rufe ich ContactsFragment nie auf (und das lässt mich wissen, dass eine Methode mit einem solchen Namen leicht als Konstruktor verwechselt werden könnte). Vielleicht behalte ich mein ContactsDb als solches und erstelle einen anderen ContactsFragment-Konstruktor? – Shyam

+0

Wow Daniel, toller Fang ... das war genau das Problem. Von nun an werde ich es in meinen Schädel sperren, dass dieser Kontext in onCreate deklariert werden sollte! Prost – Shyam

Verwandte Themen