Android SQLite Insert работает, Query не работает - PullRequest
3 голосов
/ 25 июля 2010

это мой первый пост на этом сайте, так что, надеюсь, это будет положительный опыт. У меня проблема с Android SQLite / ContentProvider, которую я бью головой об стену в течение последних 3 часов. Ниже приведен код ContentProvider:

public class IncidentProvider extends ContentProvider {

private static final UriMatcher sUriMatcher;
private static final HashMap<String, String> projectionMap;
private static final int INCIDENTS = 1;

public static final String AUTHORITY = "com.test.providers.IncidentsProvider";
public static final String TABLE_NAME = "incidents";

private static class DatabaseHelper extends SQLiteOpenHelper {

    public DatabaseHelper(Context context) {
        super(context, context.getString(R.string.database_name), null, Integer.parseInt(context.getString(R.string.database_version)));
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + TABLE_NAME + " (" 
                + Incidents.INCIDENT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," 
                + Incidents.NAME + " VARCHAR(30),"
                + Incidents.CREATE_TIME + " LONG," 
                + Incidents.LAST_UPDATE + " LONG," 
                + Incidents.IS_ACTIVE + " VARCHAR(30)" + ");");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME );
        onCreate(db);
    }

}

private DatabaseHelper dbHelper;

/**
 * Delete a row from the database
 */
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    int count;
    switch(sUriMatcher.match(uri)) {
        case INCIDENTS:
            count = db.delete(TABLE_NAME, where, whereArgs);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    db.close();
    return count;
}

/**
 * Return the content type managed by this ContentProvider
 */
@Override
public String getType(Uri uri) {
    switch(sUriMatcher.match(uri)) {
        case INCIDENTS:
            return Incidents.CONTENT_TYPE;
        default:
            throw new IllegalArgumentException("UNKNOWN URI " + uri);
    }
}

/**
 * Insert new content into a row in the database
 */
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
    if(sUriMatcher.match(uri) != INCIDENTS) 
        throw new IllegalArgumentException("UNKNOWN URI " + uri);

    ContentValues values;
    if(initialValues != null) {
        values = new ContentValues(initialValues);
    } else {
        values = new ContentValues();
    }

    SQLiteDatabase db = dbHelper.getWritableDatabase();
    long rowId = db.insert(TABLE_NAME, Incidents.NAME, values);

    if(rowId > 0) {
        Uri incidentUri = ContentUris.withAppendedId(Incidents.CONTENT_URI, rowId);
        getContext().getContentResolver().notifyChange(incidentUri, null);
        db.close();
        return incidentUri;
    }
    db.close();
    throw new SQLException("Failed to insert row into " + uri);
}

/**
 * Called when creating this ContentProvider
 */
@Override
public boolean onCreate() {
    dbHelper = new DatabaseHelper(getContext());
    return false;
}

/**
 * Called when making a query to this content provider
 */
@Override
public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {

    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

    switch(sUriMatcher.match(uri)) {
        case INCIDENTS:
            qb.setTables(TABLE_NAME);
            qb.setProjectionMap(projectionMap);
            break;
        default:
            throw new IllegalArgumentException("UNKNOWN URI " + uri);
    }

    SQLiteDatabase db = dbHelper.getWritableDatabase();

    Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);
    c.setNotificationUri(getContext().getContentResolver(), uri);
    db.close();
    return c;
}

/**
 * Called when updating a row through this content provider
 */
@Override
public int update(Uri uri, ContentValues values, String where,
        String[] whereArgs) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    int count;

    switch(sUriMatcher.match(uri)) {
        case INCIDENTS:
            count = db.update(TABLE_NAME, values, where, whereArgs);
            break;
        default:
            throw new IllegalArgumentException("UNKNOWN URI " + uri);
    }

    getContext().getContentResolver().notifyChange(uri, null);
    db.close();
    return count;
}

static {
    sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    sUriMatcher.addURI(AUTHORITY, TABLE_NAME, INCIDENTS);

    projectionMap = new HashMap<String, String>();
    projectionMap.put(Incidents.INCIDENT_ID, Incidents.INCIDENT_ID);
    projectionMap.put(Incidents.NAME, Incidents.NAME);
    projectionMap.put(Incidents.CREATE_TIME, Incidents.CREATE_TIME);
    projectionMap.put(Incidents.LAST_UPDATE, Incidents.LAST_UPDATE);
    projectionMap.put(Incidents.IS_ACTIVE, Incidents.IS_ACTIVE);
}  

}

Я также написал вспомогательный класс db, чтобы упростить взаимодействие с ContentProvider. Ниже приведены 2 примера методов DBHelper (1 для вставки, 1 для запроса).

    /**
     *  Adds a new incident to the database
     **/
 public void addNewIncident(ContentResolver contentResolver, Incident incident) {
  ContentValues contentValues = new ContentValues();
  contentValues.put(Incidents.NAME, incident.getName());
  contentValues.put(Incidents.CREATE_TIME, incident.getCreateTime());
  contentValues.put(Incidents.LAST_UPDATE, incident.getLastUpdate());
  contentValues.put(Incidents.IS_ACTIVE, incident.isActive()?"true":"false");

  contentResolver.insert(Incidents.CONTENT_URI, contentValues);

 } 

    /**
     * Retrieves all incidents from the database
     **/
    public ArrayList<Incident> getIncidents(ContentResolver contentResolver) {
  Cursor c = contentResolver.query(Incidents.CONTENT_URI, null, null, null, null);
  ArrayList<Incident> returnList = new ArrayList<Incident>();

  if(c!=null && c.moveToNext()) {
   for(int i=0; i<c.getCount(); i++) {
    c.moveToPosition(i);
    Incident incident = new Incident(c.getString(c.getColumnIndex(Incidents.NAME)));
    incident.setCreateTime(c.getLong(c.getColumnIndex(Incidents.CREATE_TIME)));
    incident.setLastUpdate(c.getLong(c.getColumnIndex(Incidents.LAST_UPDATE)));
    incident.setActive(c.getString(c.getColumnIndex(Incidents.IS_ACTIVE)).equalsIgnoreCase("true"));
    returnList.add(incident);
   }
   c.close();
  }

  return returnList;
 }

Хорошо! Итак, вот моя проблема. Я могу вставить в базу данных без проблем! Если я запрашиваю базу данных через оболочку adb, я вижу все вставляемые записи. Когда я выполняю запрос с использованием SQLiteQueryBuilder, SQLiteDatabase.rawQuery или любого другого метода запроса, возвращаемый курсор возвращается с -1. Не имеет значения, запрашиваю ли я отдельную запись или запрашиваю всю базу данных. Запрос все еще возвращается -1.

Есть идеи? Я скучаю по чему-то невероятно простому?

Заранее спасибо всем, кто хочет помочь разочарованному человеку!

UPDATE:

Ниже приведен пример кода для вставки (это работает) и запросов (это не работает)

/** 
 * Following db insert works
 */
IncidentsDB db = IncidentsDB.getInstance(); 
workingIncident.setLastUpdate(System.currentTimeMillis());     // isActive, and createTime set in constructor
db.addNewIncident(this.getContentResolver(), workingIncident);

/**
 * Following db queries do not work, cursor ends up with mCount=-1 
 */
 Cursor c = IncidentsDB.getInstance().getIncidents(this.getContentResolver());

1 Ответ

3 голосов
/ 25 июля 2010

Ну, похоже, я это исправил. Оказывается, лучше закрывать базу данных в методе финализации, а не открывать и закрывать в каждом из методов удаления, вставки, запроса и обновления, как это было в приведенном выше коде. Вот фрагмент кода для тех из вас, кто столкнулся с этой проблемой, как я:

// add SQLiteDatabase member variable to content provider
private SQLiteDatabase db;

/**
 * Delete a row from the database
 */
@Override
public int delete(Uri uri, String where, String[] whereArgs) {
    // use Content Provider's db member variable in the following code block
    int count;
    switch(sUriMatcher.match(uri)) {
        case INCIDENTS:
            count = db.delete(TABLE_NAME, where, whereArgs);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
    }
    getContext().getContentResolver().notifyChange(uri, null);
    return count;
}

Затем добавьте следующий код завершения вашему провайдеру контента

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        db.close();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...