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:
- Número máximo de filas en una tabla sqlite?
- Android - Código de error 11 al importar la base de datos Sqlite en Galaxy Note
- ¿Hay tipo Long en SQLite?
- Seguridad de base de datos Sqlite
- SQLite lectura y escritura simultánea
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
- RealmObject AND Parcelable
- Cómo obtener el tamaño de la base de datos sqlite actual o el tamaño del paquete en Android?
- En la base de datos Sqlite, Cómo insertar varias filas en la tabla al mismo tiempo
- Cómo eliminar las viejas filas de la base de datos sqlite en android?
- Android.database.sqlite.SQLiteException: no hay tal columna
- Cómo almacenar la base de datos SQLite de Android en sdcard
- OrmLite SQLiteException: ninguna tabla
- Android Jelly bean base de datos está bloqueado (código 5)
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); } //........
- ¿Cómo cambiar el icono de APK?
- Obtención de imagen de la matriz de bytes en el objeto JSON a la aplicación de Android