Reputation: 530
I am working on an Android App with a Database and I am having troubles in passing the right context to my Database Handler, as the instance of the App Context that I am passing to the Database Handler seems to be always null; as I have been working on this for hours to make it work, I would appreciate any hints or constructive Feedback to make this work.
The app crashes always with the same Null Pointer Exception:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.database.Cursor android.database.sqlite.SQLiteDatabase.rawQuery(java.lang.String, java.lang.String[])' on a null object reference
in the method DatabaseHandler.getAllItems, at this part:
try (SQLiteDatabase db = this.getWritableDatabase(GoldbekStorageApp.getInstance())) {
cursor = db.rawQuery(selectQuery, null);
}
This is my Database Handler:
enter code here
package com.example.xxx;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class DatabaseHandler extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 2;
private static final String DATABASE_NAME = "itemsManager";
private static final String TABLE_ITEMS = "items";
private static final String KEY_NO = "number";
private static final String TAG = "Database values";
private static final String KEY_NAME = "name";
private static final String KEY_EAN = "ean";
private static final String KEY_TYPE = "type";
private static final String KEY_ITEMGROUPNAME = "itemgroupname";
private static final String KEY_DESTRUCTION = "destruction";
private static final String KEY_ARCHIVED = "archived";
public static final String TAGGGG = "Datenbank" ;
private String No;
private String Ean;
private String Name;
private String Itemgroupname;
private String Type;
private Boolean Destruction;
private Boolean Archived;
public Context context;
public String uname;
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
//3rd argument to be passed is CursorFactory instance
this.context = context; // add this line to initialize your context.
}
// Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
String CREATE_ITEMS_TABLE = "CREATE TABLE " + TABLE_ITEMS + "("
+ KEY_NO + " TEXT ," + KEY_NAME + " TEXT,"
+ KEY_ITEMGROUPNAME + " TEXT,"
+ KEY_TYPE + " TEXT,"
+ KEY_EAN + " TEXT,"
+ KEY_DESTRUCTION + " BOOLEAN,"
+ KEY_ARCHIVED + " BOOLEAN" +")";
Log.d(TAG, CREATE_ITEMS_TABLE);
db.execSQL(CREATE_ITEMS_TABLE);
}
public boolean getItemByEAN(String code) {
SQLiteDatabase db = this.getWritableDatabase();
Cursor mCursor = db.rawQuery("SELECT * FROM items WHERE ean =?", new String[]{ Ean });
if (mCursor != null)
{
Log.d(TAGGGG, "Worked");
return true;
/* record exist */
}
else
{
Log.d(TAGGGG, "Did not worked");
return false;
/* record not exist */
}
}
public void checkItemAgainstDatabase(String code)
{
String selectQuery = "SELECT * FROM " + TABLE_ITEMS + " WHERE " + KEY_EAN + "='" + code + "'";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if(cursor == null)
{
Log.d(TAGGGG, "Cursor ist Null, Item not present");
return;
}
if (cursor.getCount() == 0) {
Log.d(TAGGGG, " Item not present");
} else {
Log.d(TAGGGG, " Item present");
}
db.close();
return;
/*
for (Item item : itemList) {
String itemEanToBeMatched = item.getEan();
if (itemEanToBeMatched.equals(code)) {
Toast.makeText(Context, code, Toast.LENGTH_LONG).show();
//ScanService.checkEnteredCode(code, code, content, mContext.getApplicationContext());
}
String itemNoToBeMatched = item.getNo();
if (itemNoToBeMatched.equals(code)) {
Toast.makeText(mContext, code, Toast.LENGTH_LONG).show();
//ScanService.checkEnteredCode(code, code, content, mContext.getApplicationContext());
}
else {
Toast.makeText(mContext, R.string.not_in_database, Toast.LENGTH_LONG).show();
Vibrator vibrator;
vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(3000);
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(mContext.getApplicationContext(), notification);
r.play();
break;
}
} */
}
// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_ITEMS);
// Create tables again
onCreate(db);
}
// code to add the new item
public void addItem(Item items) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NO, ""+items.getNo()); // Item Ean
values.put(KEY_EAN, ""+items.getEan()); // Item Ean
values.put(KEY_NAME, items.getName()); // Item Name
values.put(KEY_TYPE, items.getType());
//values.put(KEY_ITEMGROUPNAM, item.getItemgroupname()); // Item Groupname
values.put(String.valueOf(KEY_ARCHIVED), items.getArchived());
values.put(String.valueOf(KEY_DESTRUCTION), items.getDestruction());
// Inserting Row
db.insert(TABLE_ITEMS, null, values);
//2nd argument is String containing nullColumnHack
db.close(); // Closing database connection
}
// code to get the single contact
public Item getItem(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_ITEMS, new String[] { KEY_NO,
KEY_NAME, KEY_EAN,KEY_TYPE, String.valueOf(KEY_ARCHIVED),
String.valueOf(KEY_DESTRUCTION)}, KEY_NO + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Item item = new Item(cursor.getString(0),
cursor.getString(1), cursor.getString(2),
cursor.getString(3),cursor.getString(4),cursor.getExtras().getBoolean(String.valueOf(5)),
Boolean.getBoolean(String.valueOf(6)));
Log.d(TAGGGG, String.valueOf(item));
// return contact
return item;
}
// code to get all contacts in a list view
public List<Item> getAllItems(Context context) {
List<Item> itemList = new List<Item>() {
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(@Nullable @org.jetbrains.annotations.Nullable Object o) {
return false;
}
@NonNull
@NotNull
@Override
public Iterator<Item> iterator() {
return null;
}
@NonNull
@NotNull
@Override
public Object[] toArray() {
return new Object[0];
}
@NonNull
@NotNull
@Override
public <T> T[] toArray(@NonNull @NotNull T[] a) {
return null;
}
@Override
public boolean add(Item item) {
return false;
}
@Override
public boolean remove(@Nullable @org.jetbrains.annotations.Nullable Object o) {
return false;
}
@Override
public boolean containsAll(@NonNull @NotNull Collection<?> c) {
return false;
}
@Override
public boolean addAll(@NonNull @NotNull Collection<? extends Item> c) {
return false;
}
@Override
public boolean addAll(int index, @NonNull @NotNull Collection<? extends Item> c) {
return false;
}
@Override
public boolean removeAll(@NonNull @NotNull Collection<?> c) {
return false;
}
@Override
public boolean retainAll(@NonNull @NotNull Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public boolean equals(@Nullable @org.jetbrains.annotations.Nullable Object o) {
return false;
}
@Override
public int hashCode() {
return 0;
}
@Override
public Item get(int index) {
return null;
}
@Override
public Item set(int index, Item element) {
return null;
}
@Override
public void add(int index, Item element) {
}
@Override
public Item remove(int index) {
return null;
}
@Override
public int indexOf(@Nullable @org.jetbrains.annotations.Nullable Object o) {
return 0;
}
@Override
public int lastIndexOf(@Nullable @org.jetbrains.annotations.Nullable Object o) {
return 0;
}
@NonNull
@NotNull
@Override
public ListIterator<Item> listIterator() {
return null;
}
@NonNull
@NotNull
@Override
public ListIterator<Item> listIterator(int index) {
return null;
}
@NonNull
@NotNull
@Override
public List<Item> subList(int fromIndex, int toIndex) {
return null;
}
};
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_ITEMS;
Cursor cursor;
try (SQLiteDatabase db = this.getWritableDatabase(GoldbekStorageApp.getInstance())) {
cursor = db.rawQuery(selectQuery, null);
}
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Item item = new Item(No, Name, Itemgroupname, Ean, Type, Destruction, Archived);
item.setNo(cursor.getString(0));
item.setName(cursor.getString(1));
item.setEan(cursor.getString(2));
item.setType(cursor.getString(2));
// Adding items to list
itemList.add(item);
} while (cursor.moveToNext());
}
// return contact list
return itemList;
}
private SQLiteDatabase getWritableDatabase(GoldbekStorageApp context) {
return null;
}
// code to update the single item
public int updateItem(Item item) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NO, item.getNo());
values.put(KEY_NAME, item.getName());
values.put(KEY_EAN, item.getEan());
values.put(KEY_ITEMGROUPNAME, item.getItemgroupname());
values.put(KEY_TYPE, item.getType());
values.put(String.valueOf(KEY_DESTRUCTION), item.getDestruction());
values.put(String.valueOf(KEY_ARCHIVED), item.getArchived());
// updating row
return db.update(TABLE_ITEMS, values, KEY_NO + " = ?",
new String[] { String.valueOf(item.getNo()) });
}
// Deleting single item
public void deleteItem(Item item) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_ITEMS, KEY_NO + " = ?",
new String[] { String.valueOf(item.getNo()) });
db.close();
}
// Getting items Count
public int getItemsCount() {
String itemQuery = "SELECT * FROM " + TABLE_ITEMS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(itemQuery, null);
cursor.close();
// return count
return cursor.getCount();
}
}
This is my onCreate-Method in the MainActivity, where I am calling the
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Sentry.captureMessage("testing SDK setup");
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getPosts();
//In the following lines, I am initializing the Context of my App and passing it //to the Database Handler and the Method Call of the method in the Database //Handler
*mContext = GoldbekStorageApp.getInstance();
DatabaseHandler db = new DatabaseHandler(mContext);
List<Item> items = db.getAllItems(mContext);*
new LongOperation().execute();
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(R.id.nav_palette,
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
.setDrawerLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
This is how I define the context of the App:
import android.app.Application;
import android.content.Context;
public class GoldbekStorageApp extends Application {
private static Context mContext;
public static GoldbekStorageApp mInstance= null;
public String palNo;
public String getPalNo() {
return palNo;
}
public void setPalNo(String palNo) {
this.palNo = palNo;
}
public GoldbekStorageApp(){}
public static synchronized GoldbekStorageApp getInstance() {
if(null == mInstance){
mInstance = new GoldbekStorageApp();
}
return mInstance;
}
}
I have the slight feeling that I am failing to initialize and pass the App Context to the Database Handler, but I don´t have the slightest idea where I am failing and what´s going wrong, as I am not an expert in handling the Context in Android; hence, any hints or help would be appreciated, thanks!
Upvotes: 1
Views: 380
Reputation: 1093
You need to change your getInstance method and Ctor in GoldbekStorageApp to:
public static synchronized GoldbekStorageApp getInstance(Context con) {
if(null == mInstance){
mInstance = new GoldbekStorageApp(con);
}
return mInstance;
}
public GoldbekStorageApp(Context con){mContext = con}
Do note, I am not sure why, I just know I've read in several places that holding a static reference to the app Context is not recommended. The first time you are calling getInstance you need to make sure you are passing a valid context (i.e getApplicationContext() or MainActivity.this or something of the sort) later calls can be made with passing null as parameter since it will be ignored anyway
Upvotes: 1
Reputation: 20346
First, don't create Application
object. This is done by Android.
Static way to get 'Context' in Android?
Second, do you really need it? Activity has context. It is Context
, in fact. If you need application context, then activity has getApplicationContext()
method
Upvotes: 1
Reputation: 152827
It's not the Context
.
Instead you should remove this method:
private SQLiteDatabase getWritableDatabase(GoldbekStorageApp context) {
return null;
}
and just use SQLiteOpenHelper#getWritableDatabase()
- it does not return nulls, and you pass a Context
to it in the class's constructor.
There are a number of other problems with the code, this is a reason for the NPE when trying to invoke rawQuery()
on null.
Upvotes: 2