AutoCompleteTextView中缩略图(照片)的联系人

时间:2016-08-31 06:55:33

标签: java android autocompletetextview

我想要实现的是直截了当。当我输入时,它应列出我手机中的联系人及其缩略图(照片)。起初我能够让应用程序只列出联系人姓名。但添加以下代码后,自动完成功能无效。没有错误。

以下是一些代码:

这就是我设置我的适配器的方式

 AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            adapter = new ContactsAdapter(getApplicationContext(),  
                                                getAllContactNamesAndThumbs());
            mNameEditText.setAdapter(adapter);
        }
    });

getAllContactNamesAndThumbs方法:

private List<Map<String, Object>> getAllContactNamesAndThumbs() {
    List<Map<String, Object>> namesAndThumbs;

    // Check the SDK version and whether the permission is already granted or not.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
        namesAndThumbs = new ArrayList<Map<String, Object>>();
        //After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
    } else {
        //The permissions are granted so Get all contacts
        namesAndThumbs = new ArrayList<Map<String, Object>>();
        try {
            Cursor contactCursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    new String[]{ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
                            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                            ContactsContract.CommonDataKinds.Phone.NUMBER},
                    null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");

            if (contactCursor != null) {

                while (contactCursor.moveToNext()) {

                    long id = contactCursor.getLong(contactCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));

                    InputStream inputStream = openThumbnail(id);
                    Bitmap thumbnail;

                    if (inputStream != null) {
                        thumbnail = BitmapFactory.decodeStream(inputStream);
                    } else {
                        thumbnail = BitmapFactory.decodeResource(getResources(), R.drawable.ic_person_black_24dp);
                    }

                    //Add contact name into the list
                    Map<String, Object> datum = new HashMap<String, Object>(2);
                    datum.put("name", contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
                    datum.put("thumbnail", thumbnail);
                    namesAndThumbs.add(datum);
                }

            }
        } catch (NullPointerException e) {
            Log.e("ContactNamesAndThumbs", e.getMessage());
        }
    }
    return namesAndThumbs;
}

我使用了带有AutoCompleteTextView的ArrayAdapter。这是代码

public ContactsAdapter(Context context, List<Map<String, Object>> data) {
    super(context, -1);
    this.context = context;
    this.data = data;
}


@Override
public View getView(int position, View convertView, ViewGroup parent) {

    LayoutInflater inflater = (LayoutInflater)  
                  context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    View rowView = inflater.inflate(R.layout.single_contact, parent, false);

    TextView cName = (TextView) rowView.findViewById(R.id.tv_ContactName);
    ImageView cThumb = (ImageView) rowView.findViewById(R.id.iv_contact_thumbnail);

    cName.setText(data.get(position).get("name").toString());
    cThumb.setImageBitmap((Bitmap) data.get(position).get("thumbnail"));

    return rowView;

}

2 个答案:

答案 0 :(得分:0)

AsyncTask

中运行您的任务

执行类似

 AsyncTask.execute(new Runnable() {
     @Override
     public void run() {
         adapter = new ContactsAdapter(Activity.this, getAllContactNamesAndThumbs());
         mNameEditText.setAdapter(adapter);
     }
 });

修改

在适配器中创建一个静态类

 private static class ViewHolder {
    TextView titleTextView;

    ImageView image;
 }

并在getView

   ViewHolder holder;
   if (convertView == null) {
     holder = new ViewHolder();
     LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     View rowView = layoutInflater.inflate(R.layout.single_contact, parent, false);

   // textview and imageview initialization using view holder 
   // eg holder.titleTextView = (TextView) rowView.findViewById(R.id.titleTextView);

       convertView.setTag(holder);

    } else {
        holder = (ViewHolder) convertView.getTag();
    }

     // now set data using
     // holder.image.set..
     // holder.textView.setText

答案 1 :(得分:0)

终于想通了!我不得不扩展ContactsAdapter表单BaseAdapter而不是ArrayAdapter并实现Filterable接口。而不是使用AsycTask设置适配器,我必须在活动的oncreate方法的ui线程上运行它。

以下是我在没有AsyncTask的情况下将我的适配器设置在oncreate中的方法:

adapter = new ContactsAdapter(getApplicationContext(), getAllContactNamesAndThumbs());
autoCompleteTextView.setAdapter(adapter);

getAllContactNamesAndThumbs()方法

private List<Map<String, Object>> getAllContactNamesAndThumbs() {
    List<Map<String, Object>> namesAndThumbs;

    // Check the SDK version and whether the permission is already granted or not.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
        namesAndThumbs = new ArrayList<Map<String, Object>>();
        //After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
    } else {
        //The permissions are granted so Get all contacts
        namesAndThumbs = new ArrayList<Map<String, Object>>();
        try {
            Cursor contactCursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    new String[]{ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
                            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                            ContactsContract.CommonDataKinds.Phone.NUMBER},
                    null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");

            if (contactCursor != null) {

                while (contactCursor.moveToNext()) {

                    long id = contactCursor.getLong(contactCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));

                    InputStream inputStream = openThumbnail(id);
                    Bitmap thumbnail;

                    if (inputStream != null) {
                        thumbnail = BitmapFactory.decodeStream(inputStream);
                    } else {
                        thumbnail = BitmapFactory.decodeResource(getResources(), R.drawable.ic_person_black_24dp);
                    }

                    //Add contact name into the list
                    Map<String, Object> datum = new HashMap<String, Object>(2);
                    datum.put("name", contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
                    datum.put("thumbnail", thumbnail);
                    namesAndThumbs.add(datum);
                }
            }
        } catch (NullPointerException e) {
            Log.e("ContactNamesAndThumbs", e.getMessage());
        }
    }
    return namesAndThumbs;
}

我的ContactsAdapter类:

public class ContactsAdapter extends BaseAdapter implements Filterable{

private Context context;
private List<Map<String, Object>> originalData;
private List<Map<String, Object>> suggestionData = new ArrayList<>();
private Filter filter = new CustomFilter();

public ContactsAdapter(Context context, List<Map<String, Object>> data) {
    super();
    this.context = context;
    this.originalData = data;
}

@Override
public int getCount() {
    return suggestionData.size();
}

@Override
public Object getItem(int position) {
    return suggestionData.get(position).get("name").toString();
}

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder;

    if (convertView == null) {

        LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = layoutInflater.inflate(R.layout.single_contact, parent, false);

        holder = new ViewHolder();
        holder.cName = (TextView) convertView.findViewById(R.id.tv_ContactName);
        holder.cThumb = (ImageView) convertView.findViewById(R.id.iv_contact_thumbnail);

        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.cName.setText(suggestionData.get(position).get("name").toString());
    holder.cThumb.setImageBitmap((Bitmap) suggestionData.get(position).get("thumbnail"));

    return convertView;

}

@Override
public Filter getFilter() {
    return filter;
}


private static class ViewHolder {
    TextView cName;
    ImageView cThumb;
}

/**
 * Our Custom Filter Class.
 */
private class CustomFilter extends Filter {
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        suggestionData.clear();

        if (originalData != null && constraint != null) { // Check if the Original List and Constraint aren't null.
            for (int i = 0; i < originalData.size(); i++) {
                if (Pattern.compile(Pattern.quote(constraint.toString()),
                        Pattern.CASE_INSENSITIVE).matcher
                        (originalData.get(i).get("name").toString()).find()) { // Compare item in original list if it contains constraints.
                    suggestionData.add(originalData.get(i)); // If TRUE add item in Suggestions.
                }
            }
        }
        FilterResults results = new FilterResults(); // Create new Filter Results and return this to publishResults;
        results.values = suggestionData;
        results.count = suggestionData.size();

        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        if (results.count > 0) {
            notifyDataSetChanged();
        } else {
            notifyDataSetInvalidated();
        }
    }
}
}

<强> P.S

即使这段代码按照应有的方式工作,也会有一些小问题。一个是如果你有很多像1000这样的联系人那么它是一个很大的过程,所以应用程序可能会挂起并显示I/Choreographer: Skipped xxx frames! The application may be doing too much work on its main thread.

第二个是如果你键入一些名字并按住退格键以快速擦除,那么会出现错误:

java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes.

我仍然认为这是一个答案,因为我的主要问题已经解决了。