获取并保存联系人到 SQLite 数据库阻塞 UI 很长时间
Fetching and saving Contacts to SQLite database blocking the UI for long time
我正在使用以下代码获取所有联系人并保存在本地数据库中。
获取联系人:
ArrayList<ContactHolder> contactList = new ArrayList<ContactHolder>();
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor managedCursor = mContext.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
null, order);
int _number = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int _name = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int _id = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
while (managedCursor.moveToNext()) {
ContactHolder holder = new ContactHolder();
//String mData = Utility.filterLocaleWithAppropreateFlagsTest(mContext, managedCursor.getString(_number));
holder.setNumber(managedCursor.getString(_number).replaceAll("\s+",""));
holder.setName(managedCursor.getString(_name));
holder.setImageUrl(managedCursor.getString(_name));
contactList.add(holder);
}
在 SQLite 数据库中保存:
public List<Contact> insertContactDetails() {
ArrayList<ContactHolder> arr = Utility.getContactDetails(context);
List<Contact> serverArr = new ArrayList<Contact>();
List<ContentValues> list = new ArrayList<ContentValues>();
for (int i = 0; i < arr.size(); i++) {
String mLocaleNo = "";
ContactHolder mObject = arr.get(i);
String mData = Utility.filterLocaleWithAppropreateFlagsTest(context, mObject.getNumber().replaceAll("\s+",""));
if (mData != null) {
Contact mContact = new Contact();
ContentValues values = new ContentValues();
values.put(CONTACT_NAME, mObject.getName());
mContact.setName(mObject.getName());
values.put(CONTACT_MOBILE_NUMBER, mObject.getNumber().replaceAll("\s+",""));
values.put(CONTACT_IMAGE, mObject.getImageUrl());
ArrayList<String> extra = new ArrayList<String>();
StringTokenizer token = new StringTokenizer(mData);
while (token.hasMoreElements()) {
extra.add(String.valueOf(token.nextElement()));
}
mLocaleNo = extra.get(0);
int mLocaleFlag = Integer.parseInt(extra.get(1));
values.put(LOCALE_NUMBER, mLocaleNo);
mContact.setPhNo(mLocaleNo);
values.put(LOCALE_FLAG, mLocaleFlag);
values.put(REG_STATUS, "0");
list.add(values);
serverArr.add(mContact);
}
/*
arr.get(i).setContactStatus("0");
arr.get(i).setLocaleNumber(mLocaleNo);*/
}
ourDatabase.beginTransaction();
for (ContentValues entry : list) {
try{
long id = ourDatabase.insertOrThrow(CONTACT_TABLE, null, entry);
}catch(Exception e){
e.printStackTrace();
}
}
ourDatabase.setTransactionSuccessful();
ourDatabase.endTransaction();
return serverArr;
}
一切都按预期工作,但如果接触尺寸很大,那么实际问题就会出现在图片上,使屏幕长时间变白。
我仍然没有找到任何合适的解决方案来处理这个问题。
如果数据量很大,您应该为 save/retrieve 使用 CursorLoader。
使用 CursorLoader 有三个主要好处:
- 查询是在后台线程上为您处理的(得益于在 AsyncTaskLoader 上构建),因此大数据查询不会阻塞 UI。这是文档建议您在使用普通 Cursor 时执行的操作,但现在它是在后台完成的。
- CursorLoader 正在自动更新。除了执行初始查询外,CursorLoader 还会向您请求的数据集注册一个 ContentObserver,并在数据集发生变化时对自身调用 forceLoad()。
- 这会导致在数据发生变化时获取异步回调以更新视图。
要了解更多信息,请阅读此 Cursor Loader.
我建议仅使用 ContentValues
作为模型来处理从源到目标的联系。
如果你愿意深入挖掘,你就能找出实际问题。您正在使用 contactHolder 存储并再次检索并再次存储在 ContentValues 中,我认为这是没有必要的。只需按如下所示更改代码并查看改进。
我只是将您的代码添加到一个方法中,并在其中添加了一些更改。
获取联系人:
public static ArrayList<ContentValues> getContactDetails(final Context mContext){
ArrayList<ContentValues> contactList = new ArrayList<ContentValues>();
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor managedCursor = mContext.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
null, order);
int _number = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int _name = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int _id = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
while (managedCursor.moveToNext()) {
ContentValues values = new ContentValues();
Contact mContact = new Contact();
values.put(ContactClass.CONTACT_NAME, managedCursor.getString(_name));
values.put(ContactClass.CONTACT_MOBILE_NUMBER, managedCursor.getString(_number).replaceAll("\s+",""));
mContact.setPhNo(managedCursor.getString(_number).replaceAll("\s+",""));
mContact.setName(managedCursor.getString(_name));
contactList.add(values);
serverContactList.add(mContact);
}
}
return contactList;
}
在这里,我只是使用相同的 ContentValues class 作为模型来保存集合中的联系人,并简单地为保存在静态集合中的联系人(服务器内容)class 添加相同的数据( serverContactList),您可以从任何地方直接访问它。
注意:ContactClass.CONTACT_MOBILE_NUMBER
是您的列名。
将联系人插入数据库:
public List<Contact> insertContactDetails() {
List<ContentValues> list = Utility.getContactDetails(context);
ourDatabase.beginTransaction();
for (ContentValues entry : list) {
try{
long id = ourDatabase.insertOrThrow(CONTACT_TABLE, null, entry);
}catch(Exception e){
e.printStackTrace();
}
}
ourDatabase.setTransactionSuccessful();
ourDatabase.endTransaction();
return Utility.serverContactList;
}
如果您像其他人在这里建议的那样在后台线程中执行所有这些操作,将会使您的性能更好。
我正在使用以下代码获取所有联系人并保存在本地数据库中。
获取联系人:
ArrayList<ContactHolder> contactList = new ArrayList<ContactHolder>();
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor managedCursor = mContext.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
null, order);
int _number = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int _name = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int _id = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
while (managedCursor.moveToNext()) {
ContactHolder holder = new ContactHolder();
//String mData = Utility.filterLocaleWithAppropreateFlagsTest(mContext, managedCursor.getString(_number));
holder.setNumber(managedCursor.getString(_number).replaceAll("\s+",""));
holder.setName(managedCursor.getString(_name));
holder.setImageUrl(managedCursor.getString(_name));
contactList.add(holder);
}
在 SQLite 数据库中保存:
public List<Contact> insertContactDetails() {
ArrayList<ContactHolder> arr = Utility.getContactDetails(context);
List<Contact> serverArr = new ArrayList<Contact>();
List<ContentValues> list = new ArrayList<ContentValues>();
for (int i = 0; i < arr.size(); i++) {
String mLocaleNo = "";
ContactHolder mObject = arr.get(i);
String mData = Utility.filterLocaleWithAppropreateFlagsTest(context, mObject.getNumber().replaceAll("\s+",""));
if (mData != null) {
Contact mContact = new Contact();
ContentValues values = new ContentValues();
values.put(CONTACT_NAME, mObject.getName());
mContact.setName(mObject.getName());
values.put(CONTACT_MOBILE_NUMBER, mObject.getNumber().replaceAll("\s+",""));
values.put(CONTACT_IMAGE, mObject.getImageUrl());
ArrayList<String> extra = new ArrayList<String>();
StringTokenizer token = new StringTokenizer(mData);
while (token.hasMoreElements()) {
extra.add(String.valueOf(token.nextElement()));
}
mLocaleNo = extra.get(0);
int mLocaleFlag = Integer.parseInt(extra.get(1));
values.put(LOCALE_NUMBER, mLocaleNo);
mContact.setPhNo(mLocaleNo);
values.put(LOCALE_FLAG, mLocaleFlag);
values.put(REG_STATUS, "0");
list.add(values);
serverArr.add(mContact);
}
/*
arr.get(i).setContactStatus("0");
arr.get(i).setLocaleNumber(mLocaleNo);*/
}
ourDatabase.beginTransaction();
for (ContentValues entry : list) {
try{
long id = ourDatabase.insertOrThrow(CONTACT_TABLE, null, entry);
}catch(Exception e){
e.printStackTrace();
}
}
ourDatabase.setTransactionSuccessful();
ourDatabase.endTransaction();
return serverArr;
}
一切都按预期工作,但如果接触尺寸很大,那么实际问题就会出现在图片上,使屏幕长时间变白。
我仍然没有找到任何合适的解决方案来处理这个问题。
如果数据量很大,您应该为 save/retrieve 使用 CursorLoader。
使用 CursorLoader 有三个主要好处:
- 查询是在后台线程上为您处理的(得益于在 AsyncTaskLoader 上构建),因此大数据查询不会阻塞 UI。这是文档建议您在使用普通 Cursor 时执行的操作,但现在它是在后台完成的。
- CursorLoader 正在自动更新。除了执行初始查询外,CursorLoader 还会向您请求的数据集注册一个 ContentObserver,并在数据集发生变化时对自身调用 forceLoad()。
- 这会导致在数据发生变化时获取异步回调以更新视图。
要了解更多信息,请阅读此 Cursor Loader.
我建议仅使用 ContentValues
作为模型来处理从源到目标的联系。
如果你愿意深入挖掘,你就能找出实际问题。您正在使用 contactHolder 存储并再次检索并再次存储在 ContentValues 中,我认为这是没有必要的。只需按如下所示更改代码并查看改进。
我只是将您的代码添加到一个方法中,并在其中添加了一些更改。
获取联系人:
public static ArrayList<ContentValues> getContactDetails(final Context mContext){
ArrayList<ContentValues> contactList = new ArrayList<ContentValues>();
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor managedCursor = mContext.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
null, order);
int _number = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int _name = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int _id = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
while (managedCursor.moveToNext()) {
ContentValues values = new ContentValues();
Contact mContact = new Contact();
values.put(ContactClass.CONTACT_NAME, managedCursor.getString(_name));
values.put(ContactClass.CONTACT_MOBILE_NUMBER, managedCursor.getString(_number).replaceAll("\s+",""));
mContact.setPhNo(managedCursor.getString(_number).replaceAll("\s+",""));
mContact.setName(managedCursor.getString(_name));
contactList.add(values);
serverContactList.add(mContact);
}
}
return contactList;
}
在这里,我只是使用相同的 ContentValues class 作为模型来保存集合中的联系人,并简单地为保存在静态集合中的联系人(服务器内容)class 添加相同的数据( serverContactList),您可以从任何地方直接访问它。
注意:ContactClass.CONTACT_MOBILE_NUMBER
是您的列名。
将联系人插入数据库:
public List<Contact> insertContactDetails() {
List<ContentValues> list = Utility.getContactDetails(context);
ourDatabase.beginTransaction();
for (ContentValues entry : list) {
try{
long id = ourDatabase.insertOrThrow(CONTACT_TABLE, null, entry);
}catch(Exception e){
e.printStackTrace();
}
}
ourDatabase.setTransactionSuccessful();
ourDatabase.endTransaction();
return Utility.serverContactList;
}
如果您像其他人在这里建议的那样在后台线程中执行所有这些操作,将会使您的性能更好。