2012-11-04 51 views
2

在我的應用程序中,我正在閱讀用戶電話簿中的聯繫人,並根據用戶需要執行某些操作。從用戶電話簿導入聯繫人的活動還包含一個editText字段,用戶可以使用該字段過濾聯繫人並在其中搜索。代碼如下:當前列表視圖變爲空時顯示新的ListView

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個字母后它實際上應該。

什麼是錯誤的,消息如何延遲?

回答

0

沒有多關注你的代碼,我會說延遲的原因是你在onTextChanged方法中設置過濾的方式。適配器中的篩選是在後臺線程中完成的(performFiltering在該線程上運行),並且直到方法publishResults(在主UI線程上運行)爲止,適配器纔看到新值和篩選結果調用。

現在,在onTextchanged中,您調用帶約束的filter方法,然後立即在ListView上重新設置相同的適配器(爲什麼要這樣做?!)。當您進行測試if (clvAdapter.getCount() == 0)時,過濾很可能沒有完成,並且您的適配器仍舊具有舊值,因此if測試失敗,並且您沒有看到您在那裏設置的適配器與未找到結果 text 。當你輸入另一個字母時,將再次調用onTextChanged方法,這次適配器確實是空的,因爲if條件將是true

清理onTextchanged方法(僅調用filter)並嘗試直接在適配器中實現該特殊行。

0

我有完全相同的問題,我真的需要將頁腳添加到列表中,然後在完成過濾後將其刪除。 TextWatcher會給我一個字符延遲的結果。所以我從一個稍微不同的角度來看待這個問題。 首先我創建了一個方法,並在該方法的listview中添加了一個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(); 
} 

這可能不是最好的和最優化的做事方式,但它做的工作。我意識到自從發佈這個問題已經有一段時間了,但希望它能夠幫助任何面臨這個問題的人。歡呼聲

相關問題