I am following this AlarmClock tutorial (project .zip also available on GitHub) on how to build my alarm for Android. I fixed some code that was bad, etc, but it still doesn't work as it should.
I've been getting a lot of SQLiteDatabase leaks and I fixed them (I think), but according to my observations data is still updated wrongly every time I delete an alarm or restart the application.
There are some other minor bugs, like the one where new alarms aren't added to database at all, but that is another problem.
So, I believe problem lies somewhere here:
package com.example.vedran.valarm;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import com.example.vedran.valarm.AlarmContract.Alarm;
import java.util.ArrayList;
import java.util.List;
public class AlarmDBHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION=1;
public static final String DATABASE_NAME = "alarmclock.db";
private static AlarmDBHelper database;
private static final String SQL_CREATE_ALARM =
"CREATE TABLE " + Alarm.TABLE_NAME + " (" +
Alarm._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Alarm.COLUMN_NAME_ALARM_NAME + " TEXT," +
Alarm.COLUMN_NAME_ALARM_TIME_HOUR + " INTEGER," +
Alarm.COLUMN_NAME_ALARM_TIME_MINUTE + " INTEGER," +
Alarm.COLUMN_NAME_ALARM_REPEAT_DAYS + " TEXT," +
Alarm.COLUMN_NAME_ALARM_REPEAT_WEEKLY + " BOOLEAN," +
Alarm.COLUMN_NAME_ALARM_TONE + " TEXT," +
Alarm.COLUMN_NAME_ALARM_ENABLED + " BOOLEAN" + " )";
private static final String SQL_DELETE_ALARM =
"DROP TABLE IF EXISTS" + Alarm.TABLE_NAME;
public AlarmDBHelper(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ALARM);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(SQL_DELETE_ALARM);
onCreate(db);
}
public static synchronized AlarmDBHelper getInstance(Context context){
if(database == null){
database = new AlarmDBHelper(context.getApplicationContext());
}
return database;
}
/**
* objasnim kasnije
* @param c
* @return
*/
private AlarmModel populateModel(Cursor c){
AlarmModel model = new AlarmModel();
model.id = c.getLong(c.getColumnIndex(Alarm._ID));
model.name = c.getString(c.getColumnIndex(Alarm.COLUMN_NAME_ALARM_NAME));
model.timeHour = c.getInt(c.getColumnIndex(Alarm.COLUMN_NAME_ALARM_TIME_HOUR));
model.timeMinute = c.getInt(c.getColumnIndex(Alarm.COLUMN_NAME_ALARM_TIME_MINUTE));
model.repeatWeekly = c.getInt(c.getColumnIndex(Alarm.COLUMN_NAME_ALARM_REPEAT_WEEKLY)) != 0;
model.alarmTone = c.getString(c.getColumnIndex(Alarm.COLUMN_NAME_ALARM_TONE)) != "" ? Uri.parse(c.getString(c.getColumnIndex(Alarm.COLUMN_NAME_ALARM_TONE))) : null;
model.isEnabled = c.getInt(c.getColumnIndex(Alarm.COLUMN_NAME_ALARM_ENABLED)) != 0;
String[] repeatingDays = c.getString(c.getColumnIndex(Alarm.COLUMN_NAME_ALARM_REPEAT_DAYS)).split(",");
for(int i=0;i<repeatingDays.length;i++){
model.setRepeatingDay(i, !repeatingDays[i].equals("false"));
}
return model;
}
private ContentValues populateContent(AlarmModel model){
ContentValues values = new ContentValues();
values.put(Alarm.COLUMN_NAME_ALARM_NAME, model.name);
values.put(Alarm.COLUMN_NAME_ALARM_TIME_HOUR, model.timeHour);
values.put(Alarm.COLUMN_NAME_ALARM_TIME_MINUTE, model.timeMinute);
values.put(Alarm.COLUMN_NAME_ALARM_REPEAT_WEEKLY, model.repeatWeekly);
values.put(Alarm.COLUMN_NAME_ALARM_TONE, model.alarmTone != null ? model.alarmTone.toString() : "");
values.put(Alarm.COLUMN_NAME_ALARM_ENABLED, model.isEnabled);
StringBuilder buildRepeatingDays = new StringBuilder();
for(int i=0; i<7; i++){
buildRepeatingDays.append(model.getRepeatingDay(i));
buildRepeatingDays.append(",");
}
String repeatingDays = buildRepeatingDays.toString();
values.put(Alarm.COLUMN_NAME_ALARM_REPEAT_DAYS, repeatingDays);
return values;
}
public long createAlarm(AlarmModel model){
ContentValues values = populateContent(model);
SQLiteDatabase db = this.getWritableDatabase();
long stat = db.insert(Alarm.TABLE_NAME, null, values);
db.close();
return stat;
}
public long updateAlarm(AlarmModel model){
ContentValues values = populateContent(model);
SQLiteDatabase db = this.getWritableDatabase();
long stat = db.update(Alarm.TABLE_NAME, values, Alarm._ID + " = " + String.valueOf(model.id), null);
db.close();
return stat;
}
public AlarmModel getAlarm(long id){
SQLiteDatabase db = this.getReadableDatabase();
String select = "SELECT * FROM " + Alarm.TABLE_NAME + " WHERE " + Alarm._ID + " = " + String.valueOf(id);
Cursor c = db.rawQuery(select, null);
if(c.moveToNext()){
AlarmModel model = populateModel(c);
c.close();
db.close();
return model;
}
c.close();
db.close();
return null;
}
public List<AlarmModel> getAlarms(){
SQLiteDatabase db = this.getReadableDatabase();
String select = "SELECT * FROM " + Alarm.TABLE_NAME;
Cursor c = db.rawQuery(select, null);
List<AlarmModel> alarmList = new ArrayList<>();
while(c.moveToNext()){
alarmList.add(populateModel(c));
}
c.close();
db.close();
if(!alarmList.isEmpty()){
return alarmList;
}
return null;
}
public int deleteAlarm(long id) {
SQLiteDatabase db = this.getWritableDatabase();
/*int br = db.delete(Alarm.TABLE_NAME, Alarm._ID + " = ?",
new String[]{String.valueOf(id)});*/
int br = db.delete(Alarm.TABLE_NAME, Alarm._ID + " = " + String.valueOf(id), null);
db.close();
return br;
}
}
And here are some methods (entire Classes and Activities are too huge to add them here, but they are available on GitHub) that deal with my database:
Inside AlarmListActivity
public void setAlarmEnabled(long id, boolean isEnabled){
AlarmManagerHelper.cancelAlarms(this);
AlarmModel model = dbHelper.getAlarm(id);
if(model!=null) {
model.isEnabled = isEnabled;
dbHelper.updateAlarm(model);
}
//mAdapter.setAlarms(dbHelper.getAlarms());
//mAdapter.notifyDataSetChanged();
AlarmManagerHelper.setAlarms(this);
}
public void deleteAlarm(long id) {
final long alarmId = id;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Please confirm deletion")
.setTitle("Delete alarm?")
.setCancelable(true)
.setNegativeButton("Cancel", null)
.setPositiveButton("Ok", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//Cancel Alarms
AlarmManagerHelper.cancelAlarms(mContext);
//Delete alarm from DB by id
dbHelper.deleteAlarm(alarmId);
//Refresh the list of the alarms in the adaptor
mAdapter.setAlarms(dbHelper.getAlarms());
//Notify the adapter the data has changed
mAdapter.notifyDataSetChanged();
//Set the alarms
AlarmManagerHelper.setAlarms(mContext);
}
}).show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
mAdapter.setAlarms(dbHelper.getAlarms());
mAdapter.notifyDataSetChanged();
/*if(dbHelper.getAlarms() == null){
throw new NullPointerException("told ya db was empty!");
}*/
}
}