Android: SQLite transactions when using ContentResolver
目标:从XML数据刷新数据库
过程:
- 开始交易
- 从表中删除所有现有行
- 对于已解析的XML的每个主要元素,将行插入到主表中并获得PK
- 将主元素的每个子元素插入记录到第二个表中,以提供上一步中的FK
- 提交交易
关于db操作的相当标准的东西。问题在于CRUD操作不是在
我当时想通过使用
我不走运吗?
我已经看到,在Google I / O应用程序的源代码中,它们会覆盖
我正计划使用这种方法来查看其工作原理。我很好奇是否有人尝试过。
从Android 2.1开始,可以通过使用ContentProviderOperation相当干净地进行基于事务的多表插入,如kaciula所述。
构建ContentProviderOperation对象时,可以调用.withValueBackReference(fieldName,refNr)。当使用applyBatch应用该操作时,结果是insert()调用随附的ContentValues对象将注入一个整数。该整数将使用fieldName String进行键控,并且其值将从先前应用的ContentProviderOperation的ContentProviderResult中检索,该内容由refNr索引。
请参考下面的代码示例。在该示例中,在表1中插入一行,然后在将表2中插入该行时,将所得的ID(在本例中为" 1")用作值。为简便起见,ContentProvider未连接到数据库。在ContentProvider中,有一些适合添加事务处理的打印输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | public class BatchTestActivity extends Activity { /** Called when the activity is first created. */ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ArrayList<ContentProviderOperation> list = new ArrayList<ContentProviderOperation>(); list.add(ContentProviderOperation. newInsert(BatchContentProvider.FIRST_URI).build()); ContentValues cv = new ContentValues(); cv.put("name","second_name"); cv.put("refId", 23); // In this example,"refId" in the contentValues will be overwritten by // the result from the first insert operation, indexed by 0 list.add(ContentProviderOperation. newInsert(BatchContentProvider.SECOND_URI). withValues(cv).withValueBackReference("refId", 0).build()); try { getContentResolver().applyBatch( BatchContentProvider.AUTHORITY, list); } catch (RemoteException e) { e.printStackTrace(); } catch (OperationApplicationException e) { e.printStackTrace(); } } } public class BatchContentProvider extends ContentProvider { private static final String SCHEME ="content://"; public static final String AUTHORITY ="com.test.batch"; public static final Uri FIRST_URI = Uri.parse(SCHEME + AUTHORITY +"/" +"table1"); public static final Uri SECOND_URI = Uri.parse(SCHEME + AUTHORITY +"/" +"table2"); public ContentProviderResult[] applyBatch( ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { System.out.println("starting transaction"); ContentProviderResult[] result; try { result = super.applyBatch(operations); } catch (OperationApplicationException e) { System.out.println("aborting transaction"); throw e; } System.out.println("ending transaction"); return result; } public Uri insert(Uri uri, ContentValues values) { // this printout will have a proper value when // the second operation is applied System.out.println("" + values); return ContentUris.withAppendedId(uri, 1); } // other overrides omitted for brevity } |
好吧-因此这并非毫无目的:我可以想到的唯一方法是将startTransaction和endTransaction编码为基于URL的查询请求。
您可以获取内容提供者对象本身的实现(如果在同一过程中,则提示:您可以使用multiprocess =" true"或process =" http://developer.android.com/guide来控制提供者的过程/topics/manifest/provider-element.html),可以使用ContentProviderClient.getLocalContentProvider()强制转换为提供程序实现,该实现可以提供额外的功能,例如reset(),用于关闭和删除数据库,还可以返回自定义Transaction类具有save()和close()方法的实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class Transaction { protected Transaction (SQLiteDatabase database) { this.database = database; database.beginTransaction (); } public void save () { this.database.setTransactionSuccessful (); } public void close () { this.database.endTransaction (); } private SQLiteDatabase database; } public Transaction createTransaction () { return new Transaction (this.dbHelper.getWritableDatabase ()); } |
然后:
1 2 | ContentProviderClient client = getContentResolver ().acquireContentProviderClient (Contract.authorityLocal); Transaction tx = ((LocalContentProvider) client.getLocalContentProvider ()).createTransaction (); |