ContactsContract.CommonDataKinds.Phone CONTENT_FILTER_URI未加载正确的数据

时间:2014-09-05 10:29:26

标签: android-contentprovider android-contacts

我尝试使用搜索列表从ListView中的联系人应用列出所有可用的电话号码和显示名称。此外,如果联系人有多个电话号码,则必须在单独的列表项目中显示(因为不同的联系人不是“联系人”应用程序中的同一联系人)。

我已成功检索所有带有显示名称的电话号码并显示在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;
}

}

有人可以帮我解决吗?提前谢谢!

1 个答案:

答案 0 :(得分: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);
    }