【问题标题】:Multiple rows insert with ContentProvider使用 ContentProvider 插入多行
【发布时间】:2015-02-15 05:43:43
【问题描述】:

我需要在一个事务中插入几行。我可以使用 ContentProvider 吗?

【问题讨论】:

标签: android insert android-contentprovider


【解决方案1】:

我已经在我的应用程序中实现了这一点,这是我使用的代码的要点。

在我的内容提供程序中,我重写了 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 而不会出现问题。

【讨论】:

    【解决方案2】:

    在客户端,ContentResolver 支持bulkInsert() 方法。 ContentProvider 不一定会在单个事务中处理这些事务,因为ContentProvider 可能没有执行任何事务。

    【讨论】:

    • 据我了解,如果它没有被覆盖 - 它只会调用几个标准的“插入”方法?
    • 正确。你不知道任何给定的ContentProvider 是否会覆盖bulkInsert(),除非它是你自己的ContentProvider
    • 我认为你应该使用 ContentProviderOperations,阅读本教程grokkingandroid.com/…
    【解决方案3】:

    这里是 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;
    }
    

    【讨论】:

    • 这比从原始数据数组中调用循环中的常规插入更好吗?使用 BulkInsert 是否有性能优势?
    • @AndrewS bulkInsert() 在大型操作上要好得多。刚刚在我的应用中完成优化:applyBatch() 对多个表执行 2000 次操作需要 2000 毫秒,10 次 bulkInsert 需要 100 毫秒。
    • 我注意到您已将notifyChange 注释掉。这样做或不这样做有什么好处?
    【解决方案4】:

    我还使用替换模式插入行 - 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-05
      • 1970-01-01
      • 2011-03-11
      • 2013-01-06
      • 1970-01-01
      相关资源
      最近更新 更多