2

在我的应用程序中,我正在从用户的电话簿中读取联系人,并根据用户的需求执行一些操作。从用户电话簿中导入联系人的 Activity 还包含一个 editText 字段,用户可以使用该字段过滤联系人并搜索联系人。代码如下:

public class InviteFriendsFromContactsActivity extends Activity implements
    TextWatcher {

private EditText friendSearch;

private ArrayList<ContactInfo> contacts;

private ListView contactsListView;

private ContactsListviewAdapter clvAdapter;


public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.invite_from_contacts);

    friendSearch = (EditText) findViewById(R.id.friendsearch);
    friendSearch.addTextChangedListener(this);



    contactsListView = (ListView) findViewById(R.id.ContactsListView);

    ReadContacts();

}

void ReadContacts() {

    contacts = new ArrayList<ContactInfo>();

    Cursor cursor = getContentResolver().query(
            ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
    while (cursor.moveToNext()) {
        long contactId = cursor.getLong(cursor
                .getColumnIndex(ContactsContract.Contacts._ID));
        String name = cursor.getString(cursor
                .getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
        Cursor emails = getContentResolver().query(
                ContactsContract.CommonDataKinds.Email.CONTENT_URI,
                null,
                ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = "
                        + contactId, null, null);
        while (emails.moveToNext()) {
            // This would allow to get several email addresses, so if 1
            // contact has 2 emails, will be listed as 2 rows
            String emailAddress = emails
                    .getString(emails
                            .getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
            if (emailAddress != null)
                contacts.add(new ContactInfo(contactId, name, emailAddress));
        }
        emails.close();
    }
    cursor.close();

    clvAdapter = new ContactsListviewAdapter(getApplicationContext(),
            contacts);

    contactsListView.setAdapter(clvAdapter);

}

public void onTextChanged(CharSequence s, int start, int before, int count) {
    if (clvAdapter != null) {
        clvAdapter.getFilter().filter(s);
        contactsListView.setAdapter(clvAdapter);
    }
    if (clvAdapter.getCount() == 0) {
        ListView list = (ListView) findViewById(R.id.ContactsListView);
        list.setClickable(false);

        final List<ContactInfo> listItems = new ArrayList<ContactInfo>();
        listItems.add(new ContactInfo("No results", ""));

        ContactsListviewAdapter adapter = new ContactsListviewAdapter(
                InviteFriendsFromContactsActivity.this, listItems) {

            @Override
            public View getView(int position, View convertView,
                    ViewGroup viewGroup) {
                ContactInfo entry = listItems.get(position);

                CheckBox checkBox;
                TextView nameText;
                TextView emailText;

                LayoutInflater inflater = (LayoutInflater) InviteFriendsFromContactsActivity.this
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.row, null);

                nameText = (TextView) convertView
                        .findViewById(R.id.toptext);

                emailText = (TextView) convertView
                        .findViewById(R.id.bottomtext);

                checkBox = (CheckBox) convertView
                        .findViewById(R.id.checkBox_invited);

                checkBox.setVisibility(View.GONE);
                nameText.setText(entry.getName());
                emailText.setVisibility(View.GONE);

                convertView.setBackgroundColor(Color.WHITE);

                return convertView;
            }
        };
        list.setAdapter(adapter);
    }

}
}

另外,我的 ContactsListViewAdapter 类如下。这是一个相当大的课程,但我认为与这个问题最相关的部分是getFilter方法。

class ContactsViewHolder {

public ContactsViewHolder(TextView nameTextView, TextView emailTextView,
        CheckBox checkBox, ImageView iv) {
    super();
    this.nameTextView = nameTextView;
    this.emailTextView = emailTextView;
    this.checkBox = checkBox;
    this.iv = iv;
}

public TextView getNameTextView() {
    return nameTextView;
}

public void setNameTextView(TextView nameTextView) {
    this.nameTextView = nameTextView;
}

public TextView getEmailTextView() {
    return emailTextView;
}

public void setEmailTextView(TextView emailTextView) {
    this.emailTextView = emailTextView;
}

public CheckBox getCheckBox() {
    return checkBox;
}

public void setCheckBox(CheckBox checkBox) {
    this.checkBox = checkBox;
}

public ImageView getIv() {
    return iv;
}

public void setIv(ImageView iv) {
    this.iv = iv;
}

private TextView nameTextView;
private TextView emailTextView;
private CheckBox checkBox;
private ImageView iv;

}

public class ContactsListviewAdapter extends BaseAdapter implements Filterable {
private Context context;

private List<ContactInfo> contacts;

private List<ContactInfo> originalContacts;

private List<String> selectedEmails = new ArrayList<String>();

public ContactsListviewAdapter(Context context, List<ContactInfo> contacts) {
    this.context = context;
    this.contacts = contacts;
}

public int getCount() {
    return contacts.size();
}

public Object getItem(int position) {
    return contacts.get(position);
}

public long getItemId(int position) {
    return position;
}

public View getView(int position, View convertView, ViewGroup viewGroup) {
    ContactInfo entry = contacts.get(position);

    CheckBox checkBox;
    TextView nameText;
    TextView emailText;
    ImageView contactPic;

    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.row, null);

        nameText = (TextView) convertView.findViewById(R.id.toptext);

        emailText = (TextView) convertView.findViewById(R.id.bottomtext);

        contactPic = (ImageView) convertView.findViewById(R.id.pic);

        checkBox = (CheckBox) convertView
                .findViewById(R.id.checkBox_invited);

        // Optimization: Tag the row with it's child views, so we don't have
        // to
        // call findViewById() later when we reuse the row.
        convertView.setTag(new ContactsViewHolder(nameText, emailText,
                checkBox, contactPic));

        // If CheckBox is toggled, update the planet it is tagged with.
        checkBox.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                CheckBox cb = (CheckBox) v;
                ContactInfo contact = (ContactInfo) cb.getTag();
                contact.setChecked(cb.isChecked());

                if(contact.isChecked())
                {
                    selectedEmails.add(contact.getEmail());
                }
            }
        });
    }
    // Reuse existing row view
    else {
        // Because we use a ViewHolder, we avoid having to call
        // findViewById().
        ContactsViewHolder viewHolder = (ContactsViewHolder) convertView
                .getTag();
        checkBox = viewHolder.getCheckBox();
        nameText = viewHolder.getNameTextView();
        emailText = viewHolder.getEmailTextView();
        contactPic = viewHolder.getIv();
    }

    // Tag the CheckBox with the Contact it is displaying, so that we can
    // access the Contact in onClick() when the CheckBox is toggled.
    checkBox.setTag(entry);

    // Display contact data
    checkBox.setChecked(entry.isChecked());
    nameText.setText(entry.getName());
    emailText.setText(entry.getEmail());

    Bitmap bitmap = People.loadContactPhoto(context,
            ContentUris.withAppendedId(People.CONTENT_URI, entry.getId()),
            R.drawable.contacts, null);
    contactPic.setImageBitmap(bitmap);

    return convertView;
}

@Override
public Filter getFilter() {
    Filter filter = new Filter() {

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint,
                FilterResults results) {

            contacts = (List<ContactInfo>) results.values; // has the filtered values
            notifyDataSetChanged(); // notifies the data with new filtered values
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults(); // Holds the
                                                            // results of a
                                                            // filtering
                                                            // operation in
                                                            // values
            List<ContactInfo> FilteredArrList = new ArrayList<ContactInfo>();

            if (originalContacts == null) {
                originalContacts = new ArrayList<ContactInfo>(contacts); 
            }

            /********
             * 
             * If constraint(CharSequence that is received) is null returns
             * the mOriginalValues(Original) values else does the Filtering
             * and returns FilteredArrList(Filtered)
             * 
             ********/
            if (constraint == null || constraint.length() == 0) {

                // set the Original result to return
                results.count = originalContacts.size();
                results.values = originalContacts;
            } else {
                constraint = constraint.toString().toLowerCase();
                for (int i = 0; i < originalContacts.size(); i++) {
                    String name = originalContacts.get(i).getName();
                    if (name.toLowerCase()
                            .startsWith(constraint.toString())) {
                        FilteredArrList.add(originalContacts.get(i));
                    }
                }
                // set the Filtered result to return
                results.count = FilteredArrList.size();
                results.values = FilteredArrList;
            }
            return results;
        }
    };
    return filter;
}


public List<String> getSelectedEmails() {
    return selectedEmails;
}
}

联系人在活动中导入就好了。当我尝试搜索联系人时出现问题。当我在搜索字段中输入“x”(我的电话簿中没有以 x 开头的联系人)时,显示了 0 个联系人,No results found但未显示消息。它只会在我在“x”之后键入另一个字母后显示。通常,消息No results found总是在实际应该显示的 1 个字母之后显示。

出了什么问题,消息是如何延迟的?

4

2 回答 2

0

我遇到了完全相同的问题,我真的需要将页脚添加到列表中,然后在过滤完成后将其删除。TextWatcher 会给我一个字符延迟的结果。所以我从一个稍微不同的角度来处理这个问题。首先,我创建了一个方法并将一个添加GLobalLayoutListener到该方法中的列表视图中。

public void DoGlobalListener(){
        mTextList.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                       if(mListAdapter.isEmpty() && !mFooterAdded){
                        mTextList.addFooterView(mFooter);
                        mFooterAdded = true;
                       }else{
                        mTextList.removeFooterView(mFooter);
                        mFooterAdded = false;
                       }
                       mTextList.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    }
                });
    }

在这里,我检查adapter设置是否ListView为空,然后boolean我设置查看是否添加页脚是否设置为 false。如果两个条件都满足,我添加页脚并将其设置boolean为 true。如果不满足条件,则执行相反的操作。在它结束时,我停止它GlobalLayoutListener以确保只完成一次。然后可以在 textWatcher 的afterTextChanged方法中调用此方法,以便在每次EditText更改中的文本时运行它。

    @Override
    public void afterTextChanged(Editable s) {
    DoGlobalListener();
}

这可能不是最整洁和最优化的做事方式,但它确实可以完成工作。我意识到这个问题发布已经有一段时间了,但希望它能够帮助任何面临这个问题的人。干杯

于 2014-01-12T11:14:19.413 回答
0

无需过多查看您的代码,我会说延迟的原因是您在方法中设置过滤的onTextChanged方式。适配器中的过滤是在后台线程中完成的(在该线程上运行),并且在调用方法(在主 UI 线程上运行performFiltering)之前,适配器不会看到新值和过滤结果。publishResults

现在,在onTextchanged您调用filter带有约束的方法,然后立即重新设置相同的适配器ListView(为什么要这样做?!)。到您进行测试if (clvAdapter.getCount() == 0)时,过滤很可能尚未完成,并且您的适配器仍然具有旧值,因此if测试失败并且您看不到您在此处设置的适配器以及未找到结果文本。当您输入另一个字母时,onTextChanged将再次调用该方法,这一次适配器确实是空的,在这种if情况下将是true.

清理onTextchanged方法(只调用filter)并尝试直接在适配器中实现该特殊行。

于 2012-11-04T16:34:43.727 回答