Android 加载联系人太慢

发布于 2024-12-03 01:04:37 字数 3442 浏览 0 评论 0原文

在我的应用程序中,有 5 个旋转器填充了手机中的联系人。我使用下面的代码用联系人填充数组,然后用数组的项目填充微调器(这里只有 1 个微调器)。

当用户打开应用程序时,会填充微调器,以便用户可以为每个微调器选择一个名称。 事实是,当用户打开应用程序时,使用微调器加载布局大约需要 3 秒。在玩完代码后,我发现无论应用程序中的旋转器有多少,问题的根源都是用联系人填充数组的代码。 我还找到了速度缓慢的原因:我在我兄弟的手机上运行了该应用程序,它的打开速度与应有的速度一样快。他手机里只有30个联系人,而我有大约500个,其中大部分是Facebook联系人。那么我该如何帮助这种情况呢?

这就是问题所在,与旋转器的数量无关。如果联系人太多,这会变得很慢:

 contactName = null;
        final Context context = getApplicationContext();

        ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
        if (cur.getCount() > 0) 
        {
            while (cur.moveToNext()) {
            String idc = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
            String namec = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

            if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) 
            {
                Cursor pCur = cr.query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, 
                ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{idc}, null);
                while (pCur.moveToNext()) {
                    contactName  = pCur.getString(pCur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); 

                    myArr.add(contactName);
                } 
                pCur.close();
                }

            }
        }

        myArr.add("");
        Collections.sort(myArr);

这就是我填充每个旋转器的方式(并使它们显示先前选择的名称):

        Spinner sp1 = (Spinner) findViewById(R.id.Spinner01);
        ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, myArr);
        sp1.setAdapter(adapter1);
        sp1.setOnItemSelectedListener(new MyOnItemSelectedListener1());


        mprefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        val1 = mprefs.getString("value1", "No name");
        if (!val1.equals("No name"))  
        {
            for (int i=0; i<myArr.size(); i++)
            {
                if (val1.equals(myArr.get(i))) 
                {
                    num = i;
                }
            }
            sp1.setSelection(num);
        }
        else
        {
            sp1.setSelection(0);
        }

基于 Jesse van Assen 的想法的解决方案

事实证明问题是第二个查询。我删除了这个并为我需要的列创建了一个“投影”变量:

final String[] projection = new String[] {
                ContactsContract.Contacts._ID,
                ContactsContract.Contacts.DISPLAY_NAME,
                ContactsContract.Contacts.HAS_PHONE_NUMBER
        };
        String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + "='1'";

        ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, projection, selection, null, null);
        if (cur.getCount() > 0) 
        {
            while (cur.moveToNext()) {
            String idc = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
            String namec = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
            myArr.add(namec);
            }
        }

所以现在我有一个查询仅收集所需的记录。然而,即使使用查询的数据集和第二个查询,它也很慢。真正的解决方案是删除第二个查询,但是收集比整个数据库更少的记录是一个好主意。

in my app there are 5 spinners populated with the contacts in the phone. I am using the code below to populate an array with the contacts and then populate the spinners with the items of the array (just 1 spinner here).

When user opens the app the spinners are populated so the user can select one name for each spinner.
Thing is, it takes around 3 secs to load the layout with the spinners when user opens the app. After playing with the code i figured out that no matter how may spinners are in the app, the source of the problem is the code that populates the array with the contacts.
I also found the cause of the slowliness: i ran the app on my brothers phone and there it opened as fast as it should. He has only 30 contacts in the phone, while I have around 500, most of them are Facebook contacts. So how can I help this situation?

Here is the problem, independently of the number of spinners. In case of too many contacts, this gets slow:

 contactName = null;
        final Context context = getApplicationContext();

        ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
        if (cur.getCount() > 0) 
        {
            while (cur.moveToNext()) {
            String idc = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
            String namec = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

            if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) 
            {
                Cursor pCur = cr.query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, 
                ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{idc}, null);
                while (pCur.moveToNext()) {
                    contactName  = pCur.getString(pCur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); 

                    myArr.add(contactName);
                } 
                pCur.close();
                }

            }
        }

        myArr.add("");
        Collections.sort(myArr);

This is how I populate each spinner (and make them show the earlier selected name):

        Spinner sp1 = (Spinner) findViewById(R.id.Spinner01);
        ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, myArr);
        sp1.setAdapter(adapter1);
        sp1.setOnItemSelectedListener(new MyOnItemSelectedListener1());


        mprefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        val1 = mprefs.getString("value1", "No name");
        if (!val1.equals("No name"))  
        {
            for (int i=0; i<myArr.size(); i++)
            {
                if (val1.equals(myArr.get(i))) 
                {
                    num = i;
                }
            }
            sp1.setSelection(num);
        }
        else
        {
            sp1.setSelection(0);
        }

Solution based on the idea of Jesse van Assen:

Turned out that the problem was the second query. I deleted this one and created a "projection" variable for the columns i needed:

final String[] projection = new String[] {
                ContactsContract.Contacts._ID,
                ContactsContract.Contacts.DISPLAY_NAME,
                ContactsContract.Contacts.HAS_PHONE_NUMBER
        };
        String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + "='1'";

        ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, projection, selection, null, null);
        if (cur.getCount() > 0) 
        {
            while (cur.moveToNext()) {
            String idc = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
            String namec = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
            myArr.add(namec);
            }
        }

So now I have one query that collects only the needed records. However it was slow even with the queried dataset AND with the second query. The real solution was to remove the second query, however collecting less record than the whole database is a great idea.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

卖梦商人 2024-12-10 01:04:37

我想说你查询联系人数据的方式是错误的。

看起来您正在从数据库中获取所有联系人及其所有联系人数据,然后在 while 循环中过滤联系人。我建议从查询中执行此操作,如下所示(未测试):

Cursor cur = cr.query(
    ContactsContract.Contacts.CONTENT_URI, 
    new String[] { "_ID", "DISPLAY_NAME" },
    "HAS_PHONE_NUMBER = ?", new String[] { "1" }, 
    null);

I would say that the way you query your contacts data is wrong.

It looks like you're fetching ALL your contacts with all the contact's data from the database, and then filtering the contacts in a while loop. I would suggest doing this from within the query, something like this (not tested):

Cursor cur = cr.query(
    ContactsContract.Contacts.CONTENT_URI, 
    new String[] { "_ID", "DISPLAY_NAME" },
    "HAS_PHONE_NUMBER = ?", new String[] { "1" }, 
    null);
苏大泽ㄣ 2024-12-10 01:04:37

如果您在分配后使用 break 跳出 for 循环,您的 Spinners 将更快填充

num = i

Your Spinners would populate a lot faster if you used a break to jump out of your for-loop once you assign

num = i
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文