web-dev-qa-db-fra.com

L'application Android se bloque au démarrage: exception SQLite NullPointerException dans ContactsFragment

Je travaille sur l'intégration d'une base de données pour enregistrer et stocker les informations de contact de base à récupérer ultérieurement. Cependant, mon application plante maintenant au démarrage et je ne peux même pas vérifier si la table est en cours de création, etc. 

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) 

Code de gestionnaire de base de données:

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

}

Le logcat dit que le problème est avec SQLiteDatabase db = this.getWriteableDatabase();

Voici aussi mon Contactsfragment offensant:

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

Enfin, voici la classe ContactsDB: 

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

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

Toute aide est très appréciée - je pense que le problème réside dans le fait que mon contexte est nul. Je ne sais pas pourquoi c'est comme je l'ai défini dans mon fichier MyDBHandler. Pour le moment, je n'ai aucun moyen de vérifier que la base de données est en cours de création, et encore moins qu'elle contient des données. 

Cordialement et merci pour votre temps et votre patience, Shyam

9
Shyam

Il semble que vous ayez créé accidentellement une variable locale context au lieu d'utiliser la variable d'instance.

Ainsi, context est null lorsque vous le transmettez à MyDBHandler, donc lorsque vous appelez this.getWritableDatabase(), this est null. En conséquence, vous obtenez la NullPointerException, comme vous pouvez le voir dans le journal:

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)

Essayez de déplacer tous les codes liés à Context à onActivityCreated() pour vous assurer que vous avez une Context valide et assurez-vous d'utiliser la variable d'instance au lieu d'une variable locale:

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

}
//........
17
Daniel Nugent

make object from db class in onCreateViewHolder, méthode dans l'adaptateur pour résoudre cette erreur

0
Mahmoud Elebiary