【发布时间】:2019-03-31 07:19:46
【问题描述】:
Play 商店中有许多应用程序,显示联系人(在获得用户许可后)和每个用户末尾的公司徽标,表示用户是否在应用程序上。 此流程有助于邀请该组用户。 当我实现上述所有内容时,事情变得非常复杂,假设底部导航有一个专用操作说 Contacts,当我从已知方法(内容解析器查询)获取联系人时,首先它太慢了,所以我把联系人放到了sqlite db,但还是很慢。 如何有效地提取联系人?。就像 OYO ROOMS APP 有一个专门的底部导航操作 邀请和赚取,这正是我想要的。如果有人知道如何有效地做到这一点,请告诉我。
private void fetchContactsFromSystem() {
ContentResolver cr = getContext().getContentResolver();
Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
if (cursor != null) {
try {
final int nameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
final int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String name, number;
while (cursor.moveToNext()) {
name = cursor.getString(nameIndex);
number = cursor.getString(numberIndex);
number = number.replaceAll(" ", "");
if (!phoneNumberSet.contains(number.trim())) {
sqliteDatabaseHelper.insertData(name.trim(), number.trim());
Contact contact = new Contact();
contact.setName(name);
contact.setPhone(number);
contact.setInvited(false);
contactList.add(contact);
phoneNumberSet.add(number);
}
}
} finally {
cursor.close();
}
}
}
投影字符串数组
private static final String[] PROJECTION = new String[]{
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
};
从 sqlite 获取数据
private void setUpFromSqliteDatabase(Cursor cr) {
String name, number;
boolean isInvite;
while (cr.moveToNext()) {
name = cr.getString(0);
number = cr.getString(1);
isInvite = cr.getInt(2) == 1;
Contact contact = new Contact();
contact.setName(name);
contact.setPhone(number);
contact.setInvited(isInvite);
contactList.add(contact);
}
cr.close();
}
SQLite 帮助类
public class SqliteDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "contacts.db";
private static final String TABLE_NAME = "contacts";
public static final String NAME = "NAME";
public static final String PHONE_NUMBER = "PHONE_NUMBER";
public static final String IS_INVITED = "IS_INVITED";
public SqliteDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + TABLE_NAME +" (NAME TEXT, PHONE_NUMBER TEXT PRIMARY KEY, IS_INVITED INTEGER DEFAULT 0)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME);
onCreate(db);
}
public boolean insertData(String name,String phone) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(NAME,name);
contentValues.put(PHONE_NUMBER,phone);
long result = db.insert(TABLE_NAME,null ,contentValues);
db.close();
return result != -1;
}
public void updateInvitedData(String phoneNumber) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(IS_INVITED, 1);
db.update(TABLE_NAME, cv, "PHONE_NUMBER = ?",new String[] {phoneNumber});
db.close();
}
public Cursor getAllData() {
SQLiteDatabase db = this.getWritableDatabase();
return db.rawQuery("select * from "+TABLE_NAME,null);
}
}
【问题讨论】:
-
“首先它太慢了” - 不是我的经验。我自己测量过一次,使用
ContentResolver查询 10k 联系人花了 200 毫秒。 -
好吧,我不知道你是怎么做到的,如果你会发布一些东西,那真的很有帮助,我确实使用了 Content Resolver 和查询返回光标,我使用光标提取用户的姓名和电话号码。所有这一切都在另一个线程中。但它很慢,这就是我问的原因。有人说批量提取联系人。不知道怎么批量提取联系人,请帮帮我。
-
如果您发布了用于执行查询并构建“联系人”POJO 的代码(或者您在 Java 代码中使用它们),将会有所帮助。您是否也进行了任何类型的分析以查看瓶颈在哪里?
-
@PPartisan 我已经更新了问题并发布了使用的代码,函数 fetchContactFromSystem() 在异步线程中运行。
-
这看起来很简单。我预计最昂贵的工作将是
replaceAll()和contains()(你不需要打电话给contains或者Set,你可以做if(set.add(...)) {/*This item is being added for the first time, so update your db here*/})- 你有多少联系人查询,你发现这个过程需要多长时间?另外,insert可能会减慢你的速度 - 批处理这些并在最后做一个批量插入会更有效。
标签: android sqlite android-contacts