And*_*ers 35 android android-contentresolver android-contentprovider
我正在开发一个应用程序,我需要插入大量的联系人条目.目前约有600个联系人,共有6000个电话号码.最大的联系人有1800个电话号码.
截至今天的状态是我创建了一个自定义帐户来保存联系人,因此用户可以选择在"联系人"视图中查看联系人.
但插入触点非常缓慢.我使用ContentResolver.applyBatch插入联系人.我尝试了不同大小的ContentProviderOperation列表(100,200,400),但总运行时间约为.相同.插入所有联系人和号码大约需要30分钟!
我发现在SQlite中缓慢插入的大多数问题都会导致交易.但是因为我使用ContentResolver.applyBatch方法,所以我不控制它,我会假设ContentResolver为我负责事务管理.
所以,我的问题是:我做错了什么,或者我能做些什么来加快这个速度?
安德斯
编辑: @jcwenger:哦,我明白了.很好的解释!
那么我将首先插入raw_contacts表,然后插入带有名称和数字的数据表.我将失去的是对我在applyBatch中使用的raw_id的后向引用.
所以我必须获取新插入的raw_contacts行的所有id作为数据表中的外键吗?
jcw*_*ger 51
用ContentResolver.bulkInsert (Uri url, ContentValues[] values)而不是ApplyBatch()
ApplyBatch(1)使用事务和(2)它为整个批处理锁定ContentProvider一次,而不是每次操作锁定/解锁一次.因此,它比一次一个(非批量)快一点.
但是,由于批处理中的每个操作都可以具有不同的URI等,因此会产生大量的开销."哦,一个新的操作!我想知道它进入了什么桌子......在这里,我将插入一行......哦,一个新的操作!我想知道它在哪个表格......"无限广告.由于将URI转换为表格的大部分工作涉及大量的字符串比较,因此它显然非常慢.
相比之下,bulkInsert将整堆值应用于同一个表.它说,"批量插入......找到桌子,好吧,插入!插入!插入!插入!插入!" 快多了.
当然,它需要您的ContentResolver有效地实现bulkInsert.大多数人都这样做,除非你自己写的,在这种情况下需要一些编码.
Vir*_*ren 10
bulkInsert:对于那些感兴趣的人,这是我能够试验的代码.注意我们如何避免int/long/floats的一些分配:)这可以节省更多时间.
private int doBulkInsertOptimised(Uri uri, ContentValues values[]) {
long startTime = System.currentTimeMillis();
long endTime = 0;
//TimingInfo timingInfo = new TimingInfo(startTime);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
DatabaseUtils.InsertHelper inserter =
new DatabaseUtils.InsertHelper(db, Tables.GUYS);
// Get the numeric indexes for each of the columns that we're updating
final int guiStrColumn = inserter.getColumnIndex(Guys.STRINGCOLUMNTYPE);
final int guyDoubleColumn = inserter.getColumnIndex(Guys.DOUBLECOLUMNTYPE);
//...
final int guyIntColumn = inserter.getColumnIndex(Guys.INTEGERCOLUMUNTYPE);
db.beginTransaction();
int numInserted = 0;
try {
int len = values.length;
for (int i = 0; i < len; i++) {
inserter.prepareForInsert();
String guyID = (String)(values[i].get(Guys.GUY_ID));
inserter.bind(guiStrColumn, guyID);
// convert to double ourselves to save an allocation.
double d = ((Number)(values[i].get(Guys.DOUBLECOLUMNTYPE))).doubleValue();
inserter.bind(guyDoubleColumn, lat);
// getting the raw Object and converting it int ourselves saves
// an allocation (the alternative is ContentValues.getAsInt, which
// returns a Integer object)
int status = ((Number) values[i].get(Guys.INTEGERCOLUMUNTYPE)).intValue();
inserter.bind(guyIntColumn, status);
inserter.execute();
}
numInserted = len;
db.setTransactionSuccessful();
} finally {
db.endTransaction();
inserter.close();
endTime = System.currentTimeMillis();
if (LOGV) {
long timeTaken = (endTime - startTime);
Log.v(TAG, "Time taken to insert " + values.length + " records was " + timeTaken +
" milliseconds " + " or " + (timeTaken/1000) + "seconds");
}
}
getContext().getContentResolver().notifyChange(uri, null);
return numInserted;
}
Run Code Online (Sandbox Code Playgroud)