La aplicación de Android se bloquea al iniciar: SQLite NullPointerException en ContactsFragment

Estoy trabajando en la integración de una base de datos para guardar y almacenar la información de contacto básica para ser recuperado en un momento posterior. Sin embargo, mi aplicación se está estrellando en el inicio, así que ni siquiera puedo verificar si se está creando la tabla, 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) 

Código del manejador de base de datos:

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

El logcat dice que el problema es con SQLiteDatabase db = this.getWriteableDatabase();

Este es mi ofensivo Contactsfragment también:

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

Por último, aquí está la clase ContactsDB:

 public ContactsDb(String name, int phone, String status, String blurb) { this._name = name; this._phone = phone; this._status = status; this._blurb = blurb; 

Cualquier ayuda es muy apreciada – Creo que el problema radica en que mi contexto es nulo. Simplemente no estoy seguro de por qué sería como lo he definido en mi archivo MyDBHandler. A partir de ahora, no tengo forma de verificar que el db se está creando, y mucho menos contiene datos.

Saludos y gracias por su tiempo y paciencia, Shyam

Parece que has creado accidentalmente una variable local de context lugar de usar la variable de instancia.

Por lo tanto, el context es nulo cuando se pasa a MyDBHandler , por lo que cuando se llama this.getWritableDatabase() , this es nulo. Como resultado, obtiene la NullPointerException , como puede ver en el registro:

 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) 

Intente mover todo el código relacionado con el Context a onActivityCreated() para asegurarse de que tiene un Context válido y asegúrese de usar la variable de instancia en lugar de una variable local:

 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); } //........ 
  • La base de datos no se eliminará cuando desinstale la aplicación de Android
  • ¿Cómo puedo crear una función definida por el usuario en SQLite?
  • Cómo obtener el registro de llamadas desde fecha específica en android
  • Android Seleccionar fila por Id en Sqlite?
  • Tener varios SQLiteOpenhelper en una aplicación Android
  • Expandablelistview extiende simplecursoradapter para poblar desde sqlite
  • Ejemplos de proyectos sobre la copia de seguridad del archivo y las fotos de Sqlite en Google Drive mediante programación en Android
  • Acceso a los datos principales de iOS desde Android
  • Android SQLite Error "solicitando nombre de columna con nombre de tabla"
  • Unir tablas en android
  • Cómo almacenar la contraseña SQLcipher localmente
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.