2014-09-05 20 views
0

我想列出所有可用的電話號碼與聯繫人應用程序在ListView中的顯示名稱與搜索。此外,如果聯繫人有多個電話號碼,則必須將其顯示在單獨的列表項中(因爲聯繫人應用程序中的聯繫人不同)。ContactsContract.CommonDataKinds.Phone CONTENT_FILTER_URI不加載正確的數據

我已經成功地檢索了所有具有顯示名稱並在ListView中顯示的電話號碼。聯繫人的多個電話號碼也顯示爲單獨的聯繫人。

但是,當我搜索 - 要麼給顯示名稱提供不相關的電話號碼,要麼當我輸入單個字符時無法過濾。請在此建議。

這裏是我的代碼:

public class ContactsListFragment extends ListFragment implements 
    AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor> { 

// Defines a tag for identifying log entries 
private static final String TAG = "ContactsListFragment"; 

private ContactsAdapter mAdapter; // The main query adapter 
private String mSearchTerm; // Stores the current search query term 

// Contact selected listener that allows the activity holding this fragment to be notified of 
// a contact being selected 
private OnContactsInteractionListener mOnContactSelectedListener; 

/** 
* Fragments require an empty constructor. 
*/ 
public ContactsListFragment() {} 

@Override 
public void onCreate(Bundle savedInstanceState){ 
    super.onCreate(savedInstanceState); 

    // Let this fragment contribute menu items 
    setHasOptionsMenu(true); 

    // Create the main contacts adapter 
    mAdapter = new ContactsAdapter(getActivity()); 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ 

    // Inflate the list fragment layout 
    return inflater.inflate(R.layout.contact_list_fragment, container, false); 
} 

@Override 
public void onActivityCreated(Bundle savedInstanceState){ 
    super.onActivityCreated(savedInstanceState); 

    // Set up ListView, assign adapter and set some listeners. The adapter was previously 
    // created in onCreate(). 
    setListAdapter(mAdapter); 
    getListView().setOnItemClickListener(this); 
    getListView().setOnScrollListener(new AbsListView.OnScrollListener() { 

     @Override 
     public void onScrollStateChanged(AbsListView view, int scrollState) { 
      // TODO Auto-generated method stub 

     } 

     @Override 
     public void onScroll(AbsListView view, int firstVisibleItem, 
       int visibleItemCount, int totalItemCount) { 
      // TODO Auto-generated method stub 

     } 
    }); 
} 

@Override 
public void onAttach(Activity activity){ 
    super.onAttach(activity); 
    try{ 
     // Assign callback listener which the holding activity must implement. This is used 
     // so that when a contact item is interacted with (selected by the user) the holding 
     // activity will be notified and can take further action such as extracting the contact 
     //details and pass it to AddNewUserDialogFragment 
     mOnContactSelectedListener = (OnContactsInteractionListener) activity; 
    }catch(ClassCastException e){ 
     throw new ClassCastException(activity.toString() 
       + " must implement OnContactsInteractionListener"); 
    } 
} 

@Override 
public void onPause(){ 
    super.onPause(); 
} 

@Override 
public void onItemClick(AdapterView<?> parent, View view, int position, 
     long id) { 

    // Gets the Cursor object currently bound to the ListView 
    final Cursor cursor = mAdapter.getCursor(); 

    // Moves to the Cursor row corresponding to the ListView item that was clicked 
    cursor.moveToPosition(position); 
    final String displayName = cursor.getString(ContactMobileNumbQuery.DISPLAY_NAME); 
    final String mobileNumb = cursor.getString(ContactMobileNumbQuery.NUMBER); 
    mOnContactSelectedListener.onContactSelected(displayName, mobileNumb); 

} 
/** 
* Called when ListView selection is cleared, for example 
* when search mode is finished and the currently selected 
* contact should no longer be selected. 
*/ 
private void onSelectionCleared() { 
    // Uses callback to notify activity this contains this fragment 
    mOnContactSelectedListener.onSelectionCleared(); 

    // Clears currently checked item 
    getListView().clearChoices(); 
} 

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ 

    // Inflate the menu items 
    inflater.inflate(R.menu.contact_list_menu, menu); 
    // Locate the search item 
    MenuItem searchItem = menu.findItem(R.id.menu_search); 

    //sets up and configures the ActionBar SearchView 
    final SearchManager mSearchManager = (SearchManager)getActivity().getSystemService(Context.SEARCH_SERVICE); 

    // Retrieves the SearchView from the search menu item 
    final SearchView mSearchView = (SearchView) searchItem.getActionView(); 

    // Assign searchable info to SearchView 
    mSearchView.setSearchableInfo(mSearchManager.getSearchableInfo(getActivity().getComponentName())); 

    // Set listeners for SearchView 
    mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 

     @Override 
     public boolean onQueryTextSubmit(String query) { 
      // TODO Auto-generated method stub 
      return false; 
     } 

     @Override 
     public boolean onQueryTextChange(String newText) { 
      // Called when the action bar search text has changed. Updates 
      // the search filter, and restarts the loader to do a new query 
      // using the new search string. 
      String newFilter = !TextUtils.isEmpty(newText) ? newText : null; 

      // Don't do anything if the filter is empty 
      if(mSearchTerm == null && newText == null){ 
       return true; 
      } 

      // Don't do anything if the new filter is the same as the current filter 
      if(mSearchTerm != null && mSearchTerm.equals(newText)){ 
       return true; 
      } 

      // Updates current filter to new filter 
      mSearchTerm = newFilter; 

      // Restarts the loader. This triggers onCreateLoader(), which builds the 
      // necessary content Uri from mSearchTerm. 
      getLoaderManager().restartLoader(ContactMobileNumbQuery.QUERY_ID, null, ContactsListFragment.this); 

      return true; 
     } 
    }); 

    searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { 

     @Override 
     public boolean onMenuItemActionExpand(MenuItem item) { 
      // Nothing to do when the action item is expanded 
      return true; 
     } 

     @Override 
     public boolean onMenuItemActionCollapse(MenuItem item) { 
      // When the user collapses the SearchView the current search string is 
      // cleared and the loader restarted. 
      if(!TextUtils.isEmpty(mSearchTerm)){ 
       onSelectionCleared(); 
      } 
      mSearchTerm = null; 
      getLoaderManager().restartLoader(ContactMobileNumbQuery.QUERY_ID, null, ContactsListFragment.this); 
      return true; 
     } 
    }); 

    getLoaderManager().restartLoader(ContactMobileNumbQuery.QUERY_ID, null, ContactsListFragment.this); 
} 

@Override 
public void onSaveInstanceState(Bundle outState){ 
    super.onSaveInstanceState(outState); 
    if(!TextUtils.isEmpty(mSearchTerm)){ 
     // Saves the current search string 
     outState.putString(SearchManager.QUERY, mSearchTerm); 
    } 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item){ 

    return super.onOptionsItemSelected(item); 

} 

@Override 
public Loader<Cursor> onCreateLoader(int id, Bundle args) { 

    Log.i(TAG, "onCreateLoader starts"); 
    //If this is the loader for finding contacts in the Contacts Provider 
    if(id == ContactMobileNumbQuery.QUERY_ID){ 
     Uri contentUri; 

     // There are two types of searches, one which displays all contacts and 
     // one which filters contacts by a search query. If mSearchTerm is set 
     // then a search query has been entered and the latter should be used. 
     if(mSearchTerm == null){ 
      // Since there's no search string, use the content URI that searches the entire 
      // Contacts table 
      contentUri = ContactMobileNumbQuery.CONTENT_URI; 
     }else{ 
      // Since there's a search string, use the special content Uri that searches the 
      // Contacts table. The URI consists of a base Uri and the search string. 
      contentUri = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(mSearchTerm)); 
     } 
     // Returns a new CursorLoader for querying the Contacts table. No arguments are used 
     // for the selection clause. The search string is either encoded onto the content URI, 
     // or no contacts search string is used. The other search criteria are constants. See 
     // the ContactsQuery interface. 
     return new CursorLoader(getActivity(), 
       contentUri, 
       ContactMobileNumbQuery.PROJECTION, 
       ContactMobileNumbQuery.SELECTION, 
       null, 
       ContactMobileNumbQuery.SORT_ORDER); 
    } 
    Log.e(TAG, "onCreateLoader - incorrect ID provided (" + id + ")"); 
    return null; 
} 

@Override 
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
    // This swaps the new cursor into the adapter. 
    if(loader.getId() == ContactMobileNumbQuery.QUERY_ID){ 
     mAdapter.swapCursor(data); 
    } 
} 

@Override 
public void onLoaderReset(Loader<Cursor> loader) { 
    if(loader.getId() == ContactMobileNumbQuery.QUERY_ID){ 
     // When the loader is being reset, clear the cursor from the adapter. This allows the 
     // cursor resources to be freed. 
     mAdapter.swapCursor(null); 
    } 
} 

/** 
* This is a subclass of CursorAdapter that supports binding Cursor columns to a view layout. 
* If those items are part of search results, it will be bind to the view layout. 
*/ 
private class ContactsAdapter extends CursorAdapter implements SectionIndexer { 
    private LayoutInflater mInflater; // Stores the layout inflater 
    private TextAppearanceSpan highlightTextSpan; // Stores the highlight text appearance style 

    /** 
     * Instantiates a new Contacts Adapter. 
     * @param context A context that has access to the app's layout. 
     */ 
    public ContactsAdapter(Context context) { 
     super(context, null, 0); 

     // Stores inflater for use later 
     mInflater = LayoutInflater.from(context); 

    } 

    @Override 
    public Object[] getSections() { 
     // TODO Auto-generated method stub 
     return null; 
    } 

    @Override 
    public int getPositionForSection(int section) { 
     // TODO Auto-generated method stub 
     return 0; 
    } 

    @Override 
    public int getSectionForPosition(int position) { 
     // TODO Auto-generated method stub 
     return 0; 
    } 

    /** 
    * Binds data from the Cursor to the provided view. 
    */ 
    @Override 
    public void bindView(View view, Context context, Cursor cursor) { 
     // Gets handles to individual view resources 
     final ViewHolder holder = (ViewHolder) view.getTag(); 

     final String displayName = cursor.getString(ContactMobileNumbQuery.DISPLAY_NAME); 
     final String mobileNumb = cursor.getString(ContactMobileNumbQuery.NUMBER); 

     final int startIndex = indexOfSearchQuery(displayName); 
     if (startIndex == -1) { 
       // If the user didn't do a search, or the search string didn't match a display 
       // name, show the display name without highlighting 
       holder.text1.setText(displayName); 
       holder.mobile_text.setText(mobileNumb); 

       if (TextUtils.isEmpty(mSearchTerm)) { 

       } else { 

       } 
      }else { 
       // If the search string matched the display name, applies a SpannableString to 
       // highlight the search string with the displayed display name 

       // Wraps the display name in the SpannableString 
       final SpannableString highlightedName = new SpannableString(displayName); 

       // Sets the span to start at the starting point of the match and end at "length" 
       // characters beyond the starting point 
       highlightedName.setSpan(highlightTextSpan, startIndex, 
         startIndex + mSearchTerm.length(), 0); 

       // Binds the SpannableString to the display name View object 
       holder.text1.setText(highlightedName); 
      } 
    } 


    private int indexOfSearchQuery(String displayName) { 
     if (!TextUtils.isEmpty(mSearchTerm)) { 
      return displayName.toLowerCase(Locale.getDefault()).indexOf(
        mSearchTerm.toLowerCase(Locale.getDefault())); 
     } 
     return -1; 
    } 

    /** 
    * Overrides newView() to inflate the list item views. 
    */ 
    @Override 
    public View newView(Context context, Cursor cursor, ViewGroup viewGroup) { 
     // Inflates the list item layout. 
     final View itemLayout = mInflater.inflate(R.layout.contacts_list_view_item, viewGroup,false); 

     // Creates a new ViewHolder in which to store handles to each view resource. This 
     // allows bindView() to retrieve stored references instead of calling findViewById for 
     // each instance of the layout. 

     final ViewHolder holder = new ViewHolder(); 
     holder.text1 = (TextView) itemLayout.findViewById(android.R.id.text1); 
     holder.text2 = (TextView) itemLayout.findViewById(android.R.id.text2); 
     holder.mobile_text = (TextView) itemLayout.findViewById(R.id.mobile_text); 

     // Stores the resourceHolder instance in itemLayout. This makes resourceHolder 
     // available to bindView and other methods that receive a handle to the item view. 
     itemLayout.setTag(holder); 

     // Returns the item layout view 
     return itemLayout; 
    } 
} 

/** 
* A class that defines fields for each resource ID in the list item layout. This allows 
* ContactsAdapter.newView() to store the IDs once, when it inflates the layout, instead of 
* calling findViewById in each iteration of bindView. 
*/ 
private class ViewHolder { 
    TextView text1; 
    TextView text2; 
    TextView mobile_text; 
} 

/** 
* This interface must be implemented by any activity that loads this fragment. When an 
* interaction occurs, such as touching an item from the ListView, these callbacks will 
* be invoked to communicate the event back to the activity. 
*/ 
public interface OnContactsInteractionListener { 
    /** 
    * Called when a contact is selected from the ListView. 
    * @param contactUri The contact Uri. 
    */ 
    public void onContactSelected(String name, String mobile); 

    /** 
    * Called when the ListView selection is cleared like when 
    * a contact search is taking place or is finishing. 
    */ 
    public void onSelectionCleared(); 

    // Uses callback to notify activity this contains this fragment 
} 
/** 
* This interface defines constants used by mobile number retrieval queries. 
*/ 
public interface ContactMobileNumbQuery{ 
    final static int QUERY_ID = 1; 

    //A Content Uri for Phone table 
    final static Uri CONTENT_URI = Phone.CONTENT_URI; 

    //The search or filter query Uri 
    final static Uri FILTER_URI = Phone.CONTENT_FILTER_URI; 

    final static String SELECTION = Phone.HAS_PHONE_NUMBER + "=1" + " AND " + Phone.DISPLAY_NAME_PRIMARY + "<>''"; 

    final static String SORT_ORDER = Phone.SORT_KEY_PRIMARY; 

    final static String[] PROJECTION = { 
     Phone._ID, 
     Phone.DISPLAY_NAME_PRIMARY, 
     Phone.LOOKUP_KEY, 
     Phone.HAS_PHONE_NUMBER, 
     Phone.NUMBER, 
     Phone.TYPE, 
     SORT_ORDER 
    }; 

    final static int ID = 0; 
    final static int DISPLAY_NAME = 1; 
    final static int LOOKUP_KEY = 2; 
    final static int HAS_PHONE = 3; 
    final static int NUMBER = 4; 
    final static int TYPE = 5; 
} 

}

有人可以幫我解決這個問題?提前致謝!

回答

0

以下代碼修復了我的問題。

@Override 
    public void bindView(View view, Context context, Cursor cursor) { 
     // Gets handles to individual view resources 
     final ViewHolder holder = (ViewHolder) view.getTag(); 

     final String displayName = cursor.getString(ContactMobileNumbQuery.DISPLAY_NAME); 
     final String mobileNumb = cursor.getString(ContactMobileNumbQuery.NUMBER); 

     holder.text1.setText(displayName); 
     holder.mobile_text.setText(mobileNumb); 
    }