0

Ich erstellte eine dynamische AutoCompleteTextView in Android. Es hat die folgenden Komponenten.Kill AsyncTask aufgerufen in perfromFilter für dynamische AutoCompleteTextView

  1. ArrayAdapter mit meiner benutzerdefinierten POJO.
  2. Adaptergeräte Filterbar.
  3. Dieser Filter hat einen Aufruf an eine AsyncTask, die alle Daten basierend auf dem Zeichen oder den Einschränkungen abrufen, die es erhält.
  4. Nachdem alle Daten abgerufen wurden, analysiert die AsyncTask die Daten und gibt die Liste dann an den Filter zurück, damit sie veröffentlicht werden kann.

Szenario: Nun, wenn ich in den AutoCompleteTextView Eingabe beginnen, nachdem das erste Zeichen eingegeben wird, beginnt es von dem Asynchron-Anruf. Wenn ich dann anfange, mehr Zeichen einzugeben, ruft es für jedes Zeichen erneut das Async auf und das Ergebnis wird über Filter veröffentlicht.

Problem: Das Problem ist, dass, wenn der erste AsyncTask für das erste Zeichen aufgerufen wird, wird der Ergebnisliste in der Drop veröffentlicht unten die AutoCompleteTextView, während ich noch im Textview eingeben m. Dann muss ich darauf warten, dass die neueste Liste veröffentlicht wird, was sehr viel Zeit in Anspruch nimmt, da jedes Zeichen async ausgeführt wird.

Code: Unten ist mein Adapter, den ich benutze.

public class LocationAutoCompleteAdapter extends ArrayAdapter<LocationBean> implements Filterable { 

Context context; 
LayoutInflater inflater; 
ArrayList<LocationBean> list, tempList, suggestions; 

Filter nameFilter = new Filter() { 
    @Override 
    protected FilterResults performFiltering(CharSequence constraint) { 
     FilterResults filterResults = new FilterResults(); 
     if (constraint != null) { 
      try { 
       // Downloads location list 
       DownloadLocations exec = new DownloadLocations(); 
       String term = constraint.toString(); 
       Log.e(Constants.TAG, "CHARACTER: " + term); 
       if (exec.getStatus() == AsyncTask.Status.RUNNING) { 
        exec.cancel(true); 
       } else { 
        list = exec.execute(term).get(); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      filterResults.values = list; 
      filterResults.count = list.size(); 
     } 
     return filterResults; 
    } 

    @Override 
    protected void publishResults(CharSequence constraint, FilterResults results) { 

     List<LocationBean> filterList = (ArrayList<LocationBean>) results.values; 
     if (results != null && results.count > 0) { 
      clear(); 
      for (LocationBean locations : filterList) { 
       add(locations); 
       notifyDataSetChanged(); 
      } 
     } 
    } 
}; 

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

public LocationAutoCompleteAdapter(Context context) { 
    super(context, R.layout.location_autocomplete_list_item); 
    this.context = context; 
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    suggestions = new ArrayList<LocationBean>(); 
} 

public LocationAutoCompleteAdapter(Context context, ArrayList<LocationBean> list) { 
    super(context, R.layout.location_autocomplete_list_item, list); 
    this.context = context; 
    this.list = list; 
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    tempList = new ArrayList<LocationBean>(list); // this makes the difference. 
    suggestions = new ArrayList<LocationBean>(); 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 
    if (convertView == null) { 
     holder = new ViewHolder(); 

     convertView = inflater.inflate(R.layout.location_autocomplete_list_item, parent, false); 

     holder.name = (TextView) convertView.findViewById(R.id.autcom_name); 
     holder.state = (TextView) convertView.findViewById(R.id.autcom_state); 

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

    if (list.get(position).getState().isEmpty()) { 
     holder.state.setVisibility(View.GONE); 
    } else { 
     holder.state.setVisibility(View.VISIBLE); 
    } 
    holder.name.setText(list.get(position).getName()); 
    holder.state.setText(list.get(position).getState()); 

    return convertView; 
} 

class ViewHolder { 
    TextView name, state; 
} 

private class DownloadLocations extends AsyncTask<String, Void, ArrayList<LocationBean>> { 

    @Override 
    protected ArrayList<LocationBean> doInBackground(String... params) { 
     if (!isCancelled()) { 
      try { 
       //Create a new COUNTRY SEARCH url Ex "search.php?term=india" 
       URL url = new URL(Api.LOCATION_URL + params[0]); 

       HttpsURLConnection conn = Constants.getInitHttpsURLConnectionGET(url); 

       String locationResponse = Constants.getStringFromConnection(conn); 

       // INIT ArrayList 
       ArrayList locationList = new ArrayList<LocationBean>(); 
       locationList.clear(); 

       // PARSE RESPONSE 
       JSONObject locationResponseJsonObject = new JSONObject(locationResponse); 
       Log.e(Constants.TAG, "RESPONSE: " + locationResponseJsonObject); 

       JSONArray result = locationResponseJsonObject.getJSONArray(Constants.KEY_LOCATION_RESULTS); 

       for (int i = 0; i < result.length(); i++) { 
        JSONObject locationObject = result.getJSONObject(i); 

        String id = locationObject.getString(Constants.KEY_LOCATION_ID); 
        String state = locationObject.getString(Constants.KEY_LOCATION_STATE); 
        String name = locationObject.getString(Constants.KEY_LOCATION_NAME); 
        String district = locationObject.getString(Constants.KEY_LOCATION_TEXT); 

        locationList.add(new LocationBean(id, name, district, state)); 
       } 
       return locationList; 

      } catch (Exception e) { 
       Log.d("HUS", "EXCEPTION " + e); 
       return null; 
      } 
     } else { 
      return null; 
     } 
    } 
} 
} 

Meine Gedanken: Ich denke, dass eine laufende AsyncTask töten, bevor es das Ergebnis veröffentlicht eine gute Lösung wäre. Aber ich kann das nicht. Schlage vor, wenn du eine bessere Lösung hast oder wie ich meine erreiche.

Bitte lassen Sie mich wissen, wenn Sie das Problem nicht verstanden haben. Es ist nicht tödlich, aber es ist ein nerviger Bug.

Vielen Dank.

+0

wissen Sie keine Standort insgesamt? –

+0

@SohailZahid: es variiert immer, also, wenn ich Mumbai anfange zu tippen, wird es zuerst alle Orte holen, die mit M beginnen, dann MU, dann MUM und so weiter. Die Gesamtzahl der Orte sind mehr als Lacs, daher habe ich diesen Ansatz verwendet –

Antwort

0

Hier ist ein ich die harte Tour gelernt:

Filter ist eigentlich ähnlich wie AsyncTask. Wenn Sie eine Filter haben, benötigen Sie keine AsyncTask.

  • performFiltering läuft in einem nicht-UI Hintergrund-Thread – wie doInBackground.

  • publishResults ist in dem UI-Thread erst nach Abschluss der performFiltering – wie onPostExecute läuft.

Code Rework Ihre Logik von doInBackground direkt in performFiltering zu setzen. Dies wird Ihren Code erheblich vereinfachen und dazu bringen, dass er so funktioniert, wie Sie es möchten.

+0

Versucht dies. Es zeigt immer noch zuerst die Liste des ersten eingegebenen Zeichens und dann die neuesten Aktualisierungen im Dropdown-Menü an. –

+0

Mindestens mit 'Filter', sobald' performFiltering' ausgeführt wird, werden Filteranfragen in Warteschlange gestellt, aber nicht ausgeführt, bis die erste Anfrage beendet ist, während alle zuvor in der Warteschlange befindlichen Anfragen verworfen werden. Eine einfache Lösung besteht darin, nur dann "Filter" aufzurufen, wenn der Benutzer eine bestimmte Anzahl von Zeichen eingegeben hat. Eine kompliziertere Lösung besteht darin, einen Zeitgeber zu starten, wenn der Benutzer ein Zeichen eingibt. Wenn der Benutzer vor dem Ablauf ein anderes Zeichen eingibt, wird der Zeitgeber zurückgesetzt. Dann starten Sie die Filteranforderung nur, wenn der Benutzer für eine bestimmte Zeit inaktiv war. –

0

Sie deklarieren das DownloadLocations-Objekt jedes Mal, wenn eine Suche gestartet wird, versuchen Sie, die DownloadLocations AsyncTask als globale Variable zu deklarieren.

public class LocationAutoCompleteAdapter extends ArrayAdapter<LocationBean> implements Filterable { 

Context context; 
LayoutInflater inflater; 
ArrayList<LocationBean> list, tempList, suggestions; 
DownloadLocations exec = new DownloadLocations(); 

Filter nameFilter = new Filter() { 
    @Override 
    protected FilterResults performFiltering(CharSequence constraint) { 
     FilterResults filterResults = new FilterResults(); 
     if (constraint != null) { 
      try { 
       // Downloads location list 
       String term = constraint.toString(); 
       Log.e(Constants.TAG, "CHARACTER: " + term); 
       if (exec.getStatus() == AsyncTask.Status.RUNNING) { 
        exec.cancel(true); 
       } else { 
        exec = new DownloadLocations(); 
        list = exec.execute(term).get(); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      filterResults.values = list; 
      filterResults.count = list.size(); 
     } 
     return filterResults; 
    } 

    @Override 
    protected void publishResults(CharSequence constraint, FilterResults results) { 

     List<LocationBean> filterList = (ArrayList<LocationBean>) results.values; 
     if (results != null && results.count > 0) { 
      clear(); 
      for (LocationBean locations : filterList) { 
       add(locations); 
      } 
      notifyDataSetChanged(); 
     } 
    } 
}; 

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

public LocationAutoCompleteAdapter(Context context) { 
    super(context, R.layout.location_autocomplete_list_item); 
    this.context = context; 
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    suggestions = new ArrayList<LocationBean>(); 
} 

public LocationAutoCompleteAdapter(Context context, ArrayList<LocationBean> list) { 
    super(context, R.layout.location_autocomplete_list_item, list); 
    this.context = context; 
    this.list = list; 
    this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    tempList = new ArrayList<LocationBean>(list); // this makes the difference. 
    suggestions = new ArrayList<LocationBean>(); 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 
    if (convertView == null) { 
     holder = new ViewHolder(); 

     convertView = inflater.inflate(R.layout.location_autocomplete_list_item, parent, false); 

     holder.name = (TextView) convertView.findViewById(R.id.autcom_name); 
     holder.state = (TextView) convertView.findViewById(R.id.autcom_state); 

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

    if (list.get(position).getState().isEmpty()) { 
     holder.state.setVisibility(View.GONE); 
    } else { 
     holder.state.setVisibility(View.VISIBLE); 
    } 
    holder.name.setText(list.get(position).getName()); 
    holder.state.setText(list.get(position).getState()); 

    return convertView; 
} 

class ViewHolder { 
    TextView name, state; 
} 

private class DownloadLocations extends AsyncTask<String, Void, ArrayList<LocationBean>> { 

    @Override 
    protected ArrayList<LocationBean> doInBackground(String... params) { 
     if (!isCancelled()) { 
      try { 
       //Create a new COUNTRY SEARCH url Ex "search.php?term=india" 
       URL url = new URL(Api.LOCATION_URL + params[0]); 

       HttpsURLConnection conn = Constants.getInitHttpsURLConnectionGET(url); 

       String locationResponse = Constants.getStringFromConnection(conn); 

       // INIT ArrayList 
       ArrayList locationList = new ArrayList<LocationBean>(); 
       locationList.clear(); 

       // PARSE RESPONSE 
       JSONObject locationResponseJsonObject = new JSONObject(locationResponse); 
       Log.e(Constants.TAG, "RESPONSE: " + locationResponseJsonObject); 

       JSONArray result = locationResponseJsonObject.getJSONArray(Constants.KEY_LOCATION_RESULTS); 

       for (int i = 0; i < result.length(); i++) { 
        JSONObject locationObject = result.getJSONObject(i); 

        String id = locationObject.getString(Constants.KEY_LOCATION_ID); 
        String state = locationObject.getString(Constants.KEY_LOCATION_STATE); 
        String name = locationObject.getString(Constants.KEY_LOCATION_NAME); 
        String district = locationObject.getString(Constants.KEY_LOCATION_TEXT); 

        locationList.add(new LocationBean(id, name, district, state)); 
       } 
       return locationList; 

      } catch (Exception e) { 
       Log.d("HUS", "EXCEPTION " + e); 
       return null; 
      } 
     } else { 
      return null; 
     } 
    } 
} 

}

+0

Versuchte das. Es gibt nur die Liste für das erste Zeichen und nichts anderes zurück. –

+0

check out die Bearbeitung, die ich gemacht –

+0

versuchte es .. dint Arbeit –