2016-08-31 1 views
0

Ce que je veux réaliser est simple. Quand je tape, je devrais lister les contacts de mon téléphone avec leur vignette (photo). Au début, je pouvais faire l'application ne liste que les noms des contacts. Mais après avoir ajouté les codes ci-dessous autocomplete ne fonctionne pas. Il n'y a pas d'erreursContacts avec les miniatures (photos) dans AutoCompleteTextView

Voici un code:

Voici comment je configurer mon adaptateur

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

La méthode 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; 
} 

J'ai utilisé un ArrayAdapter avec le AutoCompleteTextView. Voici le code

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; 

} 
+0

Récupère tes contacts en utilisant _AsyncTask_ – Piyush

+0

J'ai édité mon code reflétant la réponse de @Sanoop Mais ma question principale n'a toujours pas de réponse, la chose voulue ne se passe pas. – Ali

Répondre

0

Enfin figured it out! J'ai dû étendre le formulaire ContactsAdapter BaseAdapter au lieu de ArrayAdapter et implémenter l'interface Filterable. Et au lieu de définir l'adaptateur en utilisant AsycTask je devais l'exécuter sur le thread ui dans la méthode oncreate de l'activité.

Voici comment je mis mon adaptateur dans le oncreate sans AsyncTask:

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

Et la méthode 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; 
} 

ma classe 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

Même si ce code fonctionne comme il le devrait, il y a quelques hoquets. La première est que si vous avez de nombreux contacts comme un 1000 alors c'est un gros processus de sorte que l'application peut se bloquer et afficher I/Choreographer: Skipped xxx frames! The application may be doing too much work on its main thread.

La seconde est que si vous tapez un nom et maintenez la touche de retour arrière pour effacer rapidement puis il y aura un dicton d'erreur:

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.

Je considère toujours cette réponse parce que mon principal problème a été résolu.

0

Exécutez votre tâche dans AsyncTask

donc exécuter comme

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

Modifier

Créer une classe statique dans l'adaptateur

private static class ViewHolder { 
    TextView titleTextView; 

    ImageView image; 
} 

et 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 
+0

merci. Je suppose que c'est pour se débarrasser du «trop de travail sur le thread principal». Eh bien, c'est effectivement fait. Mais le Still the ** Autocomplete ** ne montre rien quand je tape. – Ali

+0

@Ali Est-ce que vous créez une classe de viewholder? – Sanoop

+0

vous voulez dire dans l'adaptateur. Non, je ne suis pas. Est-ce nécessaire? – Ali