I have recently rolled out an update for my app and I am getting feedback from some users that their data is lost. After some analysis, I have determined that a single content provider which I use always returns an empty cursor.
I haven't change the code for the content provider itself or the code which queries it. Data format did not change. The issue only is observable on a small number of devices and it seems to be limited to Android 6.0 (predominately Samsung, but also some LG devices). It is not only that the initial data is lost, but also all consequent inserts are not persisted.
The issue can be resolved by a clean installation of the app (delete + install).
Does anyone have an idea of how can this be fixed/workaround?
I don't think it is relevant, but here is the code:
Cursor cursor = contentResolver.query(Columns.contentUri(), Columns.ALARM_QUERY_COLUMNS, null, null, Columns.DEFAULT_SORT_ORDER);
List<AlarmActiveRecord> alarms = new ArrayList<AlarmActiveRecord>();
try {
if (cursor.moveToFirst()) {
do {
alarms.add(factory.create(cursor));
} while (cursor.moveToNext());
}
} finally {
cursor.close();
}
return alarms;
And the Content Provider:
@Override
public Cursor query(Uri url, String[] projectionIn, String selection, String[] selectionArgs, String sort) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
// Generate the body of the query
Preconditions.checkArgument(sURLMatcher.match(url) == ALARMS, "Invalid URL %s", url);
qb.setTables("alarms");
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor ret;
try {
ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort);
} catch (SQLException e) {
log.e("query failed because of " + e.getMessage() + ", recreating DB");
db.execSQL("DROP TABLE IF EXISTS alarms");
// I know this is not nice to call onCreate() by ourselves :-)
mOpenHelper.onCreate(db);
ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort);
}
if (ret != null) {
ret.setNotificationUri(getContext().getContentResolver(), url);
}
return ret;
}
And the Database Helper:
public class AlarmDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "alarms.db";
private static final int DATABASE_VERSION = 5;
private final Logger log;
public AlarmDatabaseHelper(Context context, Logger log) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.log = log;
}
@Override
public void onCreate(SQLiteDatabase db) {
// @formatter:off
db.execSQL("CREATE TABLE alarms (" +
"_id INTEGER PRIMARY KEY," +
"hour INTEGER, " +
"minutes INTEGER, " +
"daysofweek INTEGER, " +
"alarmtime INTEGER, " +
"enabled INTEGER, " +
"vibrate INTEGER, " +
"message TEXT, " +
"alert TEXT, " +
"prealarm INTEGER, " +
"state STRING);");
// @formatter:on
// insert default alarms
String insertMe = "INSERT INTO alarms " + "(hour, minutes, daysofweek, alarmtime, enabled, vibrate, "
+ "message, alert, prealarm, state) VALUES ";
db.execSQL(insertMe + "(8, 30, 31, 0, 0, 1, '', '', 0, '');");
db.execSQL(insertMe + "(9, 00, 96, 0, 0, 1, '', '', 0, '');");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
log.d("Upgrading alarms database from version " + oldVersion + " to " + currentVersion
+ ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS alarms");
onCreate(db);
}
public Uri commonInsert(ContentValues values) {
SQLiteDatabase db = getWritableDatabase();
long rowId = db.insert("alarms", Columns.MESSAGE, values);
if (rowId < 0) throw new SQLException("Failed to insert row");
log.d("Added alarm rowId = " + rowId);
return ContentUris.withAppendedId(Columns.contentUri(), rowId);
}
}
from Why ContentProvider returns empty cursors after App update?
No comments:
Post a Comment