【发布时间】:2015-02-15 05:43:43
【问题描述】:
我需要在一个事务中插入几行。我可以使用 ContentProvider 吗?
【问题讨论】:
-
问题不清楚..无论如何你可以看这里developer.android.com/guide/topics/providers/…
标签: android insert android-contentprovider
我需要在一个事务中插入几行。我可以使用 ContentProvider 吗?
【问题讨论】:
标签: android insert android-contentprovider
我已经在我的应用程序中实现了这一点,这是我使用的代码的要点。
在我的内容提供程序中,我重写了 applyBatch() 方法,这是一个非常简单的重写方法:
/**
* Performs the work provided in a single transaction
*/
@Override
public ContentProviderResult[] applyBatch(
ArrayList<ContentProviderOperation> operations) {
ContentProviderResult[] result = new ContentProviderResult[operations
.size()];
int i = 0;
// Opens the database object in "write" mode.
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
// Begin a transaction
db.beginTransaction();
try {
for (ContentProviderOperation operation : operations) {
// Chain the result for back references
result[i++] = operation.apply(this, result, i);
}
db.setTransactionSuccessful();
} catch (OperationApplicationException e) {
Log.d(TAG, "batch failed: " + e.getLocalizedMessage());
} finally {
db.endTransaction();
}
return result;
}
因为要支持反向引用,所以将结果提供给下一个操作。当我真的想在这个单一事务中更改数据库中的内容时,我会遍历我的内容并执行以下操作:
operations.add(ContentProviderOperation
.newInsert(
Uri.withAppendedPath(
NotePad.Notes.CONTENT_ID_URI_BASE,
Long.toString(task.dbId)))
.withValues(task.toNotesContentValues(0, listDbId))
.build());
// Now the other table, use back reference to the id the note
// received
noteIdIndex = operations.size() - 1;
operations.add(ContentProviderOperation
.newInsert(NotePad.GTasks.CONTENT_URI)
.withValues(task.toGTasksContentValues(accountName))
.withValueBackReferences(
task.toGTasksBackRefContentValues(noteIdIndex))
.build());
您只需要记住通过调用来完成:
provider.applyBatch(operations);
这将在单个事务中执行您的工作并支持反向引用,如果您需要早期插入的 id 而不会出现问题。
【讨论】:
在客户端,ContentResolver 支持bulkInsert() 方法。 ContentProvider 不一定会在单个事务中处理这些事务,因为ContentProvider 可能没有执行任何事务。
【讨论】:
ContentProvider 是否会覆盖bulkInsert(),除非它是你自己的ContentProvider。
这里是 bulkInsert 的示例:
/**
* Perform bulkInsert with use of transaction
*/
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
int uriType = 0;
int insertCount = 0;
try {
uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = dbHelper.getWritableDatabase();
switch (uriType) {
case MEASUREMENTS:
try {
sqlDB.beginTransaction();
for (ContentValues value : values) {
long id = sqlDB.insert(Tab_Measurements.TABLE_NAME, null, value);
if (id > 0)
insertCount++;
}
sqlDB.setTransactionSuccessful();
} catch (Exception e) {
// Your error handling
} finally {
sqlDB.endTransaction();
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
// getContext().getContentResolver().notifyChange(uri, null);
} catch (Exception e) {
// Your error handling
}
return insertCount;
}
在你的代码中是这样的:
/**
* Inserts new measurement information.
*
* @param ArrayList of measurements
* @return number of inserted entries
*/
public static long bulkInsertEntries(ArrayList<Item_Measurement> readings) {
// insert only if data is set correctly
if (readings.size() == 0)
return 0;
long insertCount = 0;
try {
// insert new entries
// ArrayList<ContentValues> valueList = new ArrayList<ContentValues>();
ContentValues[] valueList = new ContentValues[readings.size()];
int i = 0;
for (Item_Measurement reading : readings) {
ContentValues values = new ContentValues();
values.put(COL_TIME_READING, reading.getTimeReading());
// ...
valueList[i++] = values;
}
// returns ID
insertCount = ContentProviderOwn.getAppContext().getContentResolver()
.bulkInsert(ContentProviderOwn.MEASUREMENTS_URI_BASE, valueList);
} catch (Exception e) {
// Your error handling
}
return insertCount;
}
【讨论】:
notifyChange 注释掉。这样做或不这样做有什么好处?
我还使用替换模式插入行 - db.insertWithOnConflict(EVENT_TABLE_NAME, null, value, SQLiteDatabase.CONFLICT_REPLACE); 如果记录已经存在,它将消除冲突
在 DatabaseHelper 中添加唯一索引
public class DataProvider extends ContentProvider {
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db){
db.execSQL(CREATE_EVENT_TABLE);
db.execSQL("CREATE UNIQUE INDEX event_idx ON " + EVENT_TABLE_NAME + " ( " + EventTable.EVENT_ID + " )");
// ...
...
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
Log.i(TAG, "bulkInsert");
if (values.length == 0)
return 0;
int insertCount = 0;
try {
switch (uriMatcher.match(uri)) {
case EVENT_LIST:
try {
db.beginTransaction();
for (ContentValues value : values) {
long id = db.insertWithOnConflict(EVENT_TABLE_NAME, null, value, SQLiteDatabase.CONFLICT_REPLACE);
if (id > 0)
insertCount++;
}
db.setTransactionSuccessful();
} catch (Exception e) {
// Your error handling
} finally {
db.endTransaction();
}
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
} catch (Exception e) {
Log.i(TAG, "Exception : " + e);
}
return insertCount;
}
然后像这样调用 bulkInsert:
ContentValues[] cvArr = new ContentValues[eventList.size()];
long insertCount = 0;
int i = 0;
for (Event event : eventList) {
ContentValues cv = new ContentValues();
cv.put(DataProvider.EventTable.EVENT_ID, event.id);
cv.put(DataProvider.EventTable.SENSOR_ID, event.sensor_id);
cv.put(DataProvider.EventTable.TIMESTAMP, event.time);
cvArr[i++] = cv;
}
// returns ID
insertCount = context.getContentResolver()
.bulkInsert(DataProvider.CONTENT_EVENT_LIST, cvArr);
【讨论】: