I have an app working with a RecyclerView and SQLite.
My database is:
public class countersDatabase extends SQLiteOpenHelper {
private static final String DB_NAME = "Counters.db";
private static final String DB_TABLE = "Counters_Table";
//Columns
private static final String ID = "ID";
private static final String ITEM_INDEX = "ITEM_INDEX";
private static final String COLOR = "COLOR";
private static final String MAXTIME = "MAXTIME";
private static final String NAME = "NAME";
private static final String TYPE = "TYPE";
private static final String USINGTIME = "USINGTIME";
private static final String CREATE_TABLE = "CREATE TABLE " + DB_TABLE + " (" +
ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + //i = 0
ITEM_INDEX + " INTEGER, " + //i = 1
COLOR + " TEXT, " + //i = 2
MAXTIME + " TEXT, " + //i = 3
NAME + " TEXT, " + //i = 4
TYPE + " TEXT, " + //i = 5
USINGTIME + " TEXT " + ") "; //i = 6
public countersDatabase(Context context) {
super(context, DB_NAME, null, 1);
};
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
onCreate(sqLiteDatabase);
}
public boolean insertData(int item_index ,String color, String maxTime, String name, String type, String usingTime) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(ITEM_INDEX, item_index);
contentValues.put(COLOR, color);
contentValues.put(MAXTIME, maxTime);
contentValues.put(NAME, name);
contentValues.put(TYPE, type);
contentValues.put(USINGTIME, usingTime);
long result = db.insert(DB_TABLE, null, contentValues);
if (result == -1) return false;
else
return true;
}
public ArrayList<Counter> getAllData() {
ArrayList<Counter> arrayList = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM " + DB_TABLE, null);
while (cursor.moveToNext()) {
int id = cursor.getInt(0);
int item_index = cursor.getInt(1);
String color = cursor.getString(2);
String maxTime = cursor.getString(3);
String name = cursor.getString(4);
String type = cursor.getString(5);
String usingTime = cursor.getString(6);
Counter counter = new Counter(id, item_index, color, maxTime, name, type, usingTime);
arrayList.add(counter);
}
return arrayList;
}
public void updateTimeOnData(int position, String time) {
SQLiteDatabase db = getWritableDatabase();
db.execSQL("UPDATE "+DB_TABLE+" SET "+USINGTIME+" = '"+time+"' WHERE "+ITEM_INDEX+" = "+position+";");
db.close();
}
public void deleteDataItem(int position) {
SQLiteDatabase db = getWritableDatabase();
db.execSQL("DELETE FROM " + DB_TABLE + " WHERE " +
ITEM_INDEX + " = " + position + ";");
db.execSQL("UPDATE " + DB_TABLE + " SET " + ITEM_INDEX + " = " +
ITEM_INDEX + " -1 " + " WHERE " + ITEM_INDEX + " > " + position + ";");
db.close();
}
}
When I try to call updateTimeOnData(int position, String time)
from CounterHolder class as follows:
public class CounterHolder extends RecyclerView.ViewHolder {
countersDatabase countersDatabase;
NumberPicker timePicker;
TextView timeLabel;
TextView txtUnderTime;
double usingHours;
double maxHours;
int counterPosition;
String counterDiffHours;
private final TextView t3_name;
private final TextView t4_type;
private final Button t5_usingTime;
private final TextView remainLabel;
private Counter counter;
private Context context;
public CounterHolder(Context context, View itemView) {
super(itemView);
(...)
itemView.setOnClickListener(view -> {
if (counter != null) {
maxHours = timeStringToDouble(counter.getMaxTime());
usingHours = timeStringToDouble(counter.getUsingTime());
counterPosition = getAdapterPosition();
TextView titleToolbarCounter = ((MainActivity)context).findViewById(R.id.titleToolbarCounter);
String name = counter.getName();
titleToolbarCounter.setText(name);
TextView usingTimeCounter = ((MainActivity)context).findViewById(R.id.txtTime);
String usingTime = counter.getUsingTime();
usingTimeCounter.setText(usingTime);
counterBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
TextView pickerLabel = ((MainActivity)context).findViewById(R.id.timePickerLabel);
pickerLabel.setText("00:30");
timeLabel = ((MainActivity)context).findViewById(R.id.txtTime);
txtUnderTime = ((MainActivity)context).findViewById(R.id.txtUnderTime);
counterDiffHours = timeDoubleToString(maxHours - usingHours);
Button minusButton = ((MainActivity)context).findViewById(R.id.minusButton);
Button plusButton = ((MainActivity)context).findViewById(R.id.plusButton);
plusButton.setOnClickListener(plusAction -> {
double preHours = timeStringToDouble((String) timeLabel.getText());
double timeInterval = timeStringToDouble((String) pickerLabel.getText());
double postHours = preHours + timeInterval;
timeLabel.setText(timeDoubleToString(postHours));
//------------ERROR NEXT LINE------------
countersDatabase.updateTimeOnData(counterPosition, timeDoubleToString(postHours)); //Line 212
counterDiffHours = timeDoubleToString(maxHours - postHours);
if (postHours/maxHours == 0) {
txtUnderTime.setText(((MainActivity)context).getResources().getString(R.string.text_under_time_ini, counterDiffHours));
} else if (postHours/maxHours <= 0.25) {
txtUnderTime.setText(((MainActivity)context).getResources().getString(R.string.text_under_time_00, counterDiffHours));
} else if (postHours/maxHours <= 0.50) {
txtUnderTime.setText(((MainActivity)context).getResources().getString(R.string.text_under_time_25, counterDiffHours));
} else if (postHours/maxHours <= 0.75) {
txtUnderTime.setText(((MainActivity)context).getResources().getString(R.string.text_under_time_50, counterDiffHours));
} else {
txtUnderTime.setText(((MainActivity)context).getResources().getString(R.string.text_under_time_75, counterDiffHours));
}
}
});
}
});
}
public void bindCounter(Counter counter) {
(...)
}
public double timeStringToDouble(String time) {
String hoursString = time.substring(0,2);
String minutesString = time.substring(3);
double hours = Double.parseDouble(hoursString);
double minutes = Double.parseDouble(minutesString);
return hours + minutes/60;
}
public String timeDoubleToString(double time) {
BigDecimal bigDecimal = new BigDecimal(String.valueOf(time));
int hours = bigDecimal.intValue();
double decimalHours = bigDecimal.subtract(new BigDecimal(hours)).doubleValue();
int minutes = (int) (decimalHours * 60);
String hoursString;
String minutesString;
if (String.valueOf(hours).length() == 2) {
hoursString = String.valueOf(hours);
} else {
hoursString = "0" + hours;
}
if (String.valueOf(minutes).length() == 2) {
minutesString = String.valueOf(minutes);
} else {
minutesString = "0" + minutes;
}
return hoursString + ":" + minutesString;
}
}
I get an error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: mycounter, PID: 32064
java.lang.NullPointerException: Attempt to invoke virtual method 'void mycounter.countersDatabase.updateTimeOnData(int, java.lang.String)' on a null object reference
at mycounter.Adapters.CounterHolder.lambda$null$3$CounterHolder(CounterHolder.java:212)
at mycounter.Adapters.-$$Lambda$CounterHolder$gWMz9kyJKjdWTqootaS6M3fBw7M.onClick(Unknown Source:8)
at android.view.View.performClick(View.java:7870)
at android.widget.TextView.performClick(TextView.java:14970)
at android.view.View.performClickInternal(View.java:7839)
at android.view.View.access$3600(View.java:886)
at android.view.View$PerformClick.run(View.java:29363)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:7948)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
I've also tried to code updateTimeOnData()
as follows:
public void updateTimeOnData(int position, String time) {
SQLiteDatabase db = getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(USINGTIME, time);
db.update(DB_TABLE, cv, ITEM_INDEX + "= ?", new String[] {String.valueOf(position)});
db.close();
}
But the same error appears...
Does anybody have idea where could be the mistake? Because if I logd counterPosition
and timeDoubleToString(postHours)
I get correct values...
You are never initialising countersDatabase
in CounterHolder
, hence the NullPointerException
.